feat(cli): add agent update command for name and labels
This commit is contained in:
@@ -1074,6 +1074,40 @@ export class DaemonClient {
|
||||
return { archivedAt: result.archivedAt };
|
||||
}
|
||||
|
||||
async updateAgent(
|
||||
agentId: string,
|
||||
updates: { name?: string; labels?: Record<string, string> }
|
||||
): Promise<void> {
|
||||
const requestId = this.createRequestId();
|
||||
const message = SessionInboundMessageSchema.parse({
|
||||
type: "update_agent_request",
|
||||
agentId,
|
||||
...(updates.name !== undefined ? { name: updates.name } : {}),
|
||||
...(updates.labels && Object.keys(updates.labels).length > 0
|
||||
? { labels: updates.labels }
|
||||
: {}),
|
||||
requestId,
|
||||
});
|
||||
const payload = await this.sendRequest({
|
||||
requestId,
|
||||
message,
|
||||
timeout: 10000,
|
||||
options: { skipQueue: true },
|
||||
select: (msg) => {
|
||||
if (msg.type !== "update_agent_response") {
|
||||
return null;
|
||||
}
|
||||
if (msg.payload.requestId !== requestId) {
|
||||
return null;
|
||||
}
|
||||
return msg.payload;
|
||||
},
|
||||
});
|
||||
if (!payload.accepted) {
|
||||
throw new Error(payload.error ?? "updateAgent rejected");
|
||||
}
|
||||
}
|
||||
|
||||
async resumeAgent(
|
||||
handle: AgentPersistenceHandle,
|
||||
overrides?: Partial<AgentSessionConfig>
|
||||
|
||||
@@ -527,6 +527,16 @@ export class AgentManager {
|
||||
this.emitState(agent);
|
||||
}
|
||||
|
||||
async setLabels(
|
||||
agentId: string,
|
||||
labels: Record<string, string>
|
||||
): Promise<void> {
|
||||
const agent = this.requireAgent(agentId);
|
||||
agent.labels = { ...agent.labels, ...labels };
|
||||
await this.persistSnapshot(agent);
|
||||
this.emitState(agent);
|
||||
}
|
||||
|
||||
notifyAgentState(agentId: string): void {
|
||||
const agent = this.agents.get(agentId);
|
||||
if (!agent || agent.internal) {
|
||||
|
||||
@@ -1125,6 +1125,15 @@ export class Session {
|
||||
await this.handleArchiveAgentRequest(msg.agentId, msg.requestId);
|
||||
break;
|
||||
|
||||
case "update_agent_request":
|
||||
await this.handleUpdateAgentRequest(
|
||||
msg.agentId,
|
||||
msg.name,
|
||||
msg.labels,
|
||||
msg.requestId
|
||||
);
|
||||
break;
|
||||
|
||||
case "set_voice_mode":
|
||||
await this.handleSetVoiceMode(msg.enabled, msg.agentId, msg.requestId);
|
||||
break;
|
||||
@@ -1506,6 +1515,88 @@ export class Session {
|
||||
});
|
||||
}
|
||||
|
||||
private async handleUpdateAgentRequest(
|
||||
agentId: string,
|
||||
name: string | undefined,
|
||||
labels: Record<string, string> | undefined,
|
||||
requestId: string
|
||||
): Promise<void> {
|
||||
this.sessionLogger.info(
|
||||
{ agentId, requestId, hasName: typeof name === "string", labelCount: labels ? Object.keys(labels).length : 0 },
|
||||
"session: update_agent_request"
|
||||
);
|
||||
|
||||
const normalizedName = name?.trim();
|
||||
const normalizedLabels =
|
||||
labels && Object.keys(labels).length > 0 ? labels : undefined;
|
||||
|
||||
if (!normalizedName && !normalizedLabels) {
|
||||
this.emit({
|
||||
type: "update_agent_response",
|
||||
payload: {
|
||||
requestId,
|
||||
agentId,
|
||||
accepted: false,
|
||||
error: "Nothing to update (provide name and/or labels)",
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const liveAgent = this.agentManager.getAgent(agentId);
|
||||
if (liveAgent) {
|
||||
if (normalizedName) {
|
||||
await this.agentManager.setTitle(agentId, normalizedName);
|
||||
}
|
||||
if (normalizedLabels) {
|
||||
await this.agentManager.setLabels(agentId, normalizedLabels);
|
||||
}
|
||||
} else {
|
||||
const existing = await this.agentStorage.get(agentId);
|
||||
if (!existing) {
|
||||
throw new Error(`Agent not found: ${agentId}`);
|
||||
}
|
||||
|
||||
await this.agentStorage.upsert({
|
||||
...existing,
|
||||
...(normalizedName ? { title: normalizedName } : {}),
|
||||
...(normalizedLabels
|
||||
? { labels: { ...existing.labels, ...normalizedLabels } }
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
|
||||
this.emit({
|
||||
type: "update_agent_response",
|
||||
payload: { requestId, agentId, accepted: true, error: null },
|
||||
});
|
||||
} catch (error: any) {
|
||||
this.sessionLogger.error(
|
||||
{ err: error, agentId, requestId },
|
||||
"session: update_agent_request error"
|
||||
);
|
||||
this.emit({
|
||||
type: "activity_log",
|
||||
payload: {
|
||||
id: uuidv4(),
|
||||
timestamp: new Date(),
|
||||
type: "error",
|
||||
content: `Failed to update agent: ${error.message}`,
|
||||
},
|
||||
});
|
||||
this.emit({
|
||||
type: "update_agent_response",
|
||||
payload: {
|
||||
requestId,
|
||||
agentId,
|
||||
accepted: false,
|
||||
error: error?.message ? String(error.message) : "Failed to update agent",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle voice mode toggle
|
||||
*/
|
||||
|
||||
@@ -422,6 +422,14 @@ export const ArchiveAgentRequestMessageSchema = z.object({
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const UpdateAgentRequestMessageSchema = z.object({
|
||||
type: z.literal("update_agent_request"),
|
||||
agentId: z.string(),
|
||||
name: z.string().optional(),
|
||||
labels: z.record(z.string()).optional(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const SetVoiceModeMessageSchema = z.object({
|
||||
type: z.literal("set_voice_mode"),
|
||||
enabled: z.boolean(),
|
||||
@@ -660,6 +668,16 @@ export const SetAgentThinkingResponseMessageSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const UpdateAgentResponseMessageSchema = z.object({
|
||||
type: z.literal("update_agent_response"),
|
||||
payload: z.object({
|
||||
requestId: z.string(),
|
||||
agentId: z.string(),
|
||||
accepted: z.boolean(),
|
||||
error: z.string().nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const SetVoiceModeResponseMessageSchema = z.object({
|
||||
type: z.literal("set_voice_mode_response"),
|
||||
payload: z.object({
|
||||
@@ -971,6 +989,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
||||
UnsubscribeAgentUpdatesMessageSchema,
|
||||
DeleteAgentRequestMessageSchema,
|
||||
ArchiveAgentRequestMessageSchema,
|
||||
UpdateAgentRequestMessageSchema,
|
||||
SetVoiceModeMessageSchema,
|
||||
SendAgentMessageRequestSchema,
|
||||
WaitForFinishRequestSchema,
|
||||
@@ -1809,6 +1828,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
||||
SetAgentModeResponseMessageSchema,
|
||||
SetAgentModelResponseMessageSchema,
|
||||
SetAgentThinkingResponseMessageSchema,
|
||||
UpdateAgentResponseMessageSchema,
|
||||
WaitForFinishResponseMessageSchema,
|
||||
AgentPermissionRequestMessageSchema,
|
||||
AgentPermissionResolvedMessageSchema,
|
||||
@@ -1878,6 +1898,7 @@ export type SendAgentMessageResponseMessage = z.infer<
|
||||
export type SetVoiceModeResponseMessage = z.infer<
|
||||
typeof SetVoiceModeResponseMessageSchema
|
||||
>;
|
||||
export type UpdateAgentResponseMessage = z.infer<typeof UpdateAgentResponseMessageSchema>;
|
||||
export type WaitForFinishResponseMessage = z.infer<
|
||||
typeof WaitForFinishResponseMessageSchema
|
||||
>;
|
||||
@@ -1917,6 +1938,7 @@ export type SpeechModelsDownloadRequestMessage = z.infer<
|
||||
>;
|
||||
export type ResumeAgentRequestMessage = z.infer<typeof ResumeAgentRequestMessageSchema>;
|
||||
export type DeleteAgentRequestMessage = z.infer<typeof DeleteAgentRequestMessageSchema>;
|
||||
export type UpdateAgentRequestMessage = z.infer<typeof UpdateAgentRequestMessageSchema>;
|
||||
export type InitializeAgentRequestMessage = z.infer<typeof InitializeAgentRequestMessageSchema>;
|
||||
export type SetAgentModeRequestMessage = z.infer<typeof SetAgentModeRequestMessageSchema>;
|
||||
export type SetAgentModelRequestMessage = z.infer<typeof SetAgentModelRequestMessageSchema>;
|
||||
|
||||
Reference in New Issue
Block a user