mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-12 14:05:08 +10:00
refactor(api): introduce mapAgentEnvironmentError oRPC middleware (finding 1)
Replace 12 near-identical try/catch blocks in threads/actions/attachments/messages handlers with a single AnyMiddleware that maps the AGENT_ENVIRONMENT_UNAVAILABLE sentinel to PRECONDITION_FAILED ORPCError. Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import z from "zod";
|
||||
import { protectedProcedure } from "../../context";
|
||||
import { isAgentEnvironmentUnavailable, throwUnavailable } from "./routing";
|
||||
import { mapAgentEnvironmentError } from "./routing";
|
||||
import { agentService } from "./service";
|
||||
|
||||
export const actionsRouter = {
|
||||
@@ -13,12 +13,8 @@ export const actionsRouter = {
|
||||
summary: "Restore agent action snapshot",
|
||||
})
|
||||
.input(z.object({ id: z.string() }))
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.actions.revert({ id: input.id, userId: context.user.id });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.actions.revert({ id: input.id, userId: context.user.id });
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import z from "zod";
|
||||
import { protectedProcedure } from "../../context";
|
||||
import { storageUploadRateLimit } from "../../middleware/rate-limit";
|
||||
import { isAgentEnvironmentUnavailable, throwUnavailable } from "./routing";
|
||||
import { mapAgentEnvironmentError } from "./routing";
|
||||
import { agentService } from "./service";
|
||||
|
||||
function base64ToUint8Array(value: string) {
|
||||
@@ -26,19 +26,15 @@ export const attachmentsRouter = {
|
||||
}),
|
||||
)
|
||||
.use(storageUploadRateLimit)
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.attachments.create({
|
||||
userId: context.user.id,
|
||||
threadId: input.threadId,
|
||||
filename: input.filename,
|
||||
mediaType: input.mediaType,
|
||||
data: base64ToUint8Array(input.data),
|
||||
});
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.attachments.create({
|
||||
userId: context.user.id,
|
||||
threadId: input.threadId,
|
||||
filename: input.filename,
|
||||
mediaType: input.mediaType,
|
||||
data: base64ToUint8Array(input.data),
|
||||
});
|
||||
}),
|
||||
|
||||
delete: protectedProcedure
|
||||
@@ -51,12 +47,8 @@ export const attachmentsRouter = {
|
||||
})
|
||||
.input(z.object({ id: z.string() }))
|
||||
.output(z.void())
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
await agentService.attachments.delete({ id: input.id, userId: context.user.id });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
await agentService.attachments.delete({ id: input.id, userId: context.user.id });
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { UIMessage } from "ai";
|
||||
import z from "zod";
|
||||
import { protectedProcedure } from "../../context";
|
||||
import { aiRequestRateLimit } from "../../middleware/rate-limit";
|
||||
import { isAgentEnvironmentUnavailable, isUiMessage, throwUnavailable } from "./routing";
|
||||
import { isUiMessage, mapAgentEnvironmentError } from "./routing";
|
||||
import { agentService } from "./service";
|
||||
|
||||
export const messagesRouter = {
|
||||
@@ -22,18 +22,14 @@ export const messagesRouter = {
|
||||
}),
|
||||
)
|
||||
.use(aiRequestRateLimit)
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.messages.send({
|
||||
userId: context.user.id,
|
||||
threadId: input.threadId,
|
||||
message: input.message,
|
||||
...(input.attachmentIds ? { attachmentIds: input.attachmentIds } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.messages.send({
|
||||
userId: context.user.id,
|
||||
threadId: input.threadId,
|
||||
message: input.message,
|
||||
...(input.attachmentIds ? { attachmentIds: input.attachmentIds } : {}),
|
||||
});
|
||||
}),
|
||||
|
||||
stop: protectedProcedure
|
||||
@@ -51,17 +47,13 @@ export const messagesRouter = {
|
||||
}),
|
||||
)
|
||||
.output(z.void())
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
await agentService.messages.stop({
|
||||
userId: context.user.id,
|
||||
threadId: input.threadId,
|
||||
...(input.partialMessage ? { partialMessage: input.partialMessage } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
await agentService.messages.stop({
|
||||
userId: context.user.id,
|
||||
threadId: input.threadId,
|
||||
...(input.partialMessage ? { partialMessage: input.partialMessage } : {}),
|
||||
});
|
||||
}),
|
||||
|
||||
resume: protectedProcedure
|
||||
@@ -73,12 +65,8 @@ export const messagesRouter = {
|
||||
summary: "Resume agent message stream",
|
||||
})
|
||||
.input(z.object({ threadId: z.string() }))
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.messages.resume({ userId: context.user.id, threadId: input.threadId });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.messages.resume({ userId: context.user.id, threadId: input.threadId });
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { AnyMiddleware } from "@orpc/server";
|
||||
import type { UIMessage } from "ai";
|
||||
import { ORPCError } from "@orpc/client";
|
||||
|
||||
@@ -21,3 +22,13 @@ export function isUiMessage(value: unknown): value is UIMessage {
|
||||
Array.isArray(message.parts)
|
||||
);
|
||||
}
|
||||
|
||||
// ponytail: single middleware replaces 12 near-identical try/catch blocks across agent route handlers
|
||||
export const mapAgentEnvironmentError: AnyMiddleware = async ({ next }) => {
|
||||
try {
|
||||
return await next();
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import z from "zod";
|
||||
import { protectedProcedure } from "../../context";
|
||||
import { isAgentEnvironmentUnavailable, throwUnavailable } from "./routing";
|
||||
import { mapAgentEnvironmentError } from "./routing";
|
||||
import { agentService } from "./service";
|
||||
|
||||
export const threadsRouter = {
|
||||
@@ -12,13 +12,9 @@ export const threadsRouter = {
|
||||
operationId: "listAgentThreads",
|
||||
summary: "List agent threads",
|
||||
})
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context }) => {
|
||||
try {
|
||||
return await agentService.threads.list({ userId: context.user.id });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.threads.list({ userId: context.user.id });
|
||||
}),
|
||||
|
||||
create: protectedProcedure
|
||||
@@ -30,18 +26,14 @@ export const threadsRouter = {
|
||||
summary: "Create agent thread",
|
||||
})
|
||||
.input(z.object({ aiProviderId: z.string().optional(), sourceResumeId: z.string().optional() }))
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.threads.create({
|
||||
userId: context.user.id,
|
||||
locale: context.locale,
|
||||
...(input.aiProviderId ? { aiProviderId: input.aiProviderId } : {}),
|
||||
...(input.sourceResumeId ? { sourceResumeId: input.sourceResumeId } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.threads.create({
|
||||
userId: context.user.id,
|
||||
locale: context.locale,
|
||||
...(input.aiProviderId ? { aiProviderId: input.aiProviderId } : {}),
|
||||
...(input.sourceResumeId ? { sourceResumeId: input.sourceResumeId } : {}),
|
||||
});
|
||||
}),
|
||||
|
||||
getOrCreateForResume: protectedProcedure
|
||||
@@ -53,17 +45,13 @@ export const threadsRouter = {
|
||||
summary: "Get or create an in-resume agent thread",
|
||||
})
|
||||
.input(z.object({ resumeId: z.string(), aiProviderId: z.string().optional() }))
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.threads.getOrCreateForResume({
|
||||
userId: context.user.id,
|
||||
resumeId: input.resumeId,
|
||||
...(input.aiProviderId ? { aiProviderId: input.aiProviderId } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.threads.getOrCreateForResume({
|
||||
userId: context.user.id,
|
||||
resumeId: input.resumeId,
|
||||
...(input.aiProviderId ? { aiProviderId: input.aiProviderId } : {}),
|
||||
});
|
||||
}),
|
||||
|
||||
get: protectedProcedure
|
||||
@@ -75,13 +63,9 @@ export const threadsRouter = {
|
||||
summary: "Get agent thread",
|
||||
})
|
||||
.input(z.object({ id: z.string() }))
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
return await agentService.threads.get({ id: input.id, userId: context.user.id });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
return await agentService.threads.get({ id: input.id, userId: context.user.id });
|
||||
}),
|
||||
|
||||
archive: protectedProcedure
|
||||
@@ -94,13 +78,9 @@ export const threadsRouter = {
|
||||
})
|
||||
.input(z.object({ id: z.string() }))
|
||||
.output(z.void())
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
await agentService.threads.archive({ id: input.id, userId: context.user.id });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
await agentService.threads.archive({ id: input.id, userId: context.user.id });
|
||||
}),
|
||||
|
||||
delete: protectedProcedure
|
||||
@@ -113,12 +93,8 @@ export const threadsRouter = {
|
||||
})
|
||||
.input(z.object({ id: z.string() }))
|
||||
.output(z.void())
|
||||
.use(mapAgentEnvironmentError)
|
||||
.handler(async ({ context, input }) => {
|
||||
try {
|
||||
await agentService.threads.delete({ id: input.id, userId: context.user.id });
|
||||
} catch (error) {
|
||||
if (isAgentEnvironmentUnavailable(error)) throwUnavailable();
|
||||
throw error;
|
||||
}
|
||||
await agentService.threads.delete({ id: input.id, userId: context.user.id });
|
||||
}),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user