mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-11 10:57:07 +00:00
feat(plugins): agents and workspaces carry plugin metadata
Plugins had nowhere to keep their own data on an agent or workspace, so Phase 5 and 6 surfaces would each have invented a side store. Both now hold an opaque Record<string, JsonValue> that Paseo stores, snapshots and hands to hooks without reading a key. Set at creation or changed with agent.metadata.update.request / workspace.metadata.update.request (top-level keys replace, null removes). Persisted on the agent and workspace records, so it survives a restart. Reaches agent.create.before (which may add to it), agent.open.before (read-only), agent.create.after and workspace.create.before/after. Gated once on server_info.features.entityMetadata; the client throws "Update the host" instead of sending to a host without it.
This commit is contained in:
@@ -303,6 +303,9 @@ import type {
|
||||
// unknown avoids zod-aot's recursive z.json() object-codegen regression.
|
||||
const JsonWireValueSchema = z.unknown() as z.ZodType<JsonValue>;
|
||||
|
||||
/** Plugin-owned data on an agent or workspace. Paseo stores it and never reads a key. */
|
||||
const EntityMetadataSchema = z.record(z.string(), JsonWireValueSchema);
|
||||
|
||||
export const AgentStatusSchema = z.enum(AGENT_LIFECYCLE_STATUSES);
|
||||
|
||||
const AgentModeSchema: z.ZodType<AgentMode> = z.object({
|
||||
@@ -922,6 +925,7 @@ export const AgentSnapshotPayloadSchema = z.object({
|
||||
lastError: z.string().optional(),
|
||||
title: z.string().nullable(),
|
||||
labels: z.record(z.string(), z.string()).default({}),
|
||||
metadata: EntityMetadataSchema.optional(),
|
||||
requiresAttention: z.boolean().optional(),
|
||||
attentionReason: z.enum(["finished", "error", "permission"]).nullable().optional(),
|
||||
attentionTimestamp: z.string().nullable().optional(),
|
||||
@@ -1071,6 +1075,22 @@ export const WorkspaceTitleSetRequestSchema = z.object({
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const AgentMetadataUpdateRequestSchema = z.object({
|
||||
type: z.literal("agent.metadata.update.request"),
|
||||
agentId: z.string(),
|
||||
// Top-level keys replace; null removes the key.
|
||||
patch: EntityMetadataSchema,
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const WorkspaceMetadataUpdateRequestSchema = z.object({
|
||||
type: z.literal("workspace.metadata.update.request"),
|
||||
workspaceId: z.string(),
|
||||
// Top-level keys replace; null removes the key.
|
||||
patch: EntityMetadataSchema,
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const WorkspacePinSetRequestSchema = z.object({
|
||||
type: z.literal("workspace.pin.set.request"),
|
||||
workspaceId: z.string(),
|
||||
@@ -1847,6 +1867,7 @@ export const CreateAgentRequestMessageSchema = z.object({
|
||||
// Omitted on agent-scoped creation, the caller agent's own value applies.
|
||||
background: z.boolean().optional(),
|
||||
labels: z.record(z.string(), z.string()).default({}),
|
||||
metadata: EntityMetadataSchema.optional(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
@@ -2225,6 +2246,28 @@ export const WorkspaceTitleSetResponseSchema = z.object({
|
||||
payload: WorkspaceTitleSetResponsePayloadSchema,
|
||||
});
|
||||
|
||||
export const AgentMetadataUpdateResponseSchema = z.object({
|
||||
type: z.literal("agent.metadata.update.response"),
|
||||
payload: z.object({
|
||||
requestId: z.string(),
|
||||
agentId: z.string(),
|
||||
accepted: z.boolean(),
|
||||
metadata: EntityMetadataSchema.nullable(),
|
||||
error: z.string().nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const WorkspaceMetadataUpdateResponseSchema = z.object({
|
||||
type: z.literal("workspace.metadata.update.response"),
|
||||
payload: z.object({
|
||||
requestId: z.string(),
|
||||
workspaceId: z.string(),
|
||||
accepted: z.boolean(),
|
||||
metadata: EntityMetadataSchema.nullable(),
|
||||
error: z.string().nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const WorkspacePinSetResponsePayloadSchema = z.object({
|
||||
requestId: z.string(),
|
||||
workspaceId: z.string(),
|
||||
@@ -2780,6 +2823,7 @@ export const WorkspaceCreateRequestSchema = z.object({
|
||||
idempotencyKey: z.string().min(1).max(512).optional(),
|
||||
// Optional user-set title applied to the created workspace.
|
||||
title: z.string().optional(),
|
||||
metadata: EntityMetadataSchema.optional(),
|
||||
// Optional prompt context for workspace-level name/branch generation.
|
||||
firstAgentContext: FirstAgentContextSchema.optional(),
|
||||
// Retained for wire parsing; public internal creation is no longer supported.
|
||||
@@ -3377,6 +3421,8 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
||||
ProjectIconSetRequestSchema,
|
||||
ProjectRemoveRequestSchema,
|
||||
WorkspaceTitleSetRequestSchema,
|
||||
AgentMetadataUpdateRequestSchema,
|
||||
WorkspaceMetadataUpdateRequestSchema,
|
||||
WorkspacePinSetRequestSchema,
|
||||
WorkspaceLabelListRequestSchema,
|
||||
WorkspaceLabelAssignmentSetRequestSchema,
|
||||
@@ -3917,6 +3963,7 @@ export const ServerInfoStatusPayloadSchema = z
|
||||
explicitEventSubscriptions: z.boolean().optional(),
|
||||
ownedSubscriptions: z.boolean().optional(),
|
||||
providerOptionControls: z.boolean().optional(),
|
||||
entityMetadata: z.boolean().optional(),
|
||||
binaryChunkingV1: z.boolean().optional(),
|
||||
workspaceSetupObservation: z.boolean().optional(),
|
||||
workspaceSortTimes: z.boolean().optional(),
|
||||
@@ -4251,6 +4298,7 @@ export const WorkspaceDescriptorPayloadSchema = z
|
||||
pinnedAt: z.string().nullable().optional(),
|
||||
// COMPAT(workspaceLabels): added in v0.5.0, remove optional after 2027-08-14.
|
||||
labels: z.array(z.string()).optional(),
|
||||
metadata: EntityMetadataSchema.optional(),
|
||||
// Retained for wire parsing of older daemon descriptors.
|
||||
internal: z.boolean().optional(),
|
||||
background: z.boolean().optional(),
|
||||
@@ -7267,6 +7315,8 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
||||
ProjectIconSetResponseSchema,
|
||||
ProjectRemoveResponseSchema,
|
||||
WorkspaceTitleSetResponseSchema,
|
||||
AgentMetadataUpdateResponseSchema,
|
||||
WorkspaceMetadataUpdateResponseSchema,
|
||||
WorkspacePinSetResponseSchema,
|
||||
WorkspaceRecoveryInspectResponseSchema,
|
||||
WorkspaceRecoveryRestoreResponseSchema,
|
||||
@@ -7636,6 +7686,10 @@ export type ProjectIconSetRequest = z.infer<typeof ProjectIconSetRequestSchema>;
|
||||
export type ProjectRemoveRequest = z.infer<typeof ProjectRemoveRequestSchema>;
|
||||
export type WorkspaceTitleSetRequest = z.infer<typeof WorkspaceTitleSetRequestSchema>;
|
||||
export type WorkspacePinSetRequest = z.infer<typeof WorkspacePinSetRequestSchema>;
|
||||
export type AgentMetadataUpdateRequest = z.infer<typeof AgentMetadataUpdateRequestSchema>;
|
||||
export type WorkspaceMetadataUpdateRequest = z.infer<typeof WorkspaceMetadataUpdateRequestSchema>;
|
||||
export type AgentMetadataUpdateResponse = z.infer<typeof AgentMetadataUpdateResponseSchema>;
|
||||
export type WorkspaceMetadataUpdateResponse = z.infer<typeof WorkspaceMetadataUpdateResponseSchema>;
|
||||
export type WorkspaceRecoveryInspectRequest = z.infer<typeof WorkspaceRecoveryInspectRequestSchema>;
|
||||
export type WorkspaceRecoveryRestoreRequest = z.infer<typeof WorkspaceRecoveryRestoreRequestSchema>;
|
||||
export type SetAgentModeRequestMessage = z.infer<typeof SetAgentModeRequestMessageSchema>;
|
||||
|
||||
Reference in New Issue
Block a user