mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
bot comments
This commit is contained in:
parent
6b8838e623
commit
26f0ff67fc
@ -1,4 +1,4 @@
|
||||
import { callReducerStrict, opt } from "@/lib/ai/spacetimedb-client";
|
||||
import { callReducerStrict } from "@/lib/ai/spacetimedb-client";
|
||||
import { assertIsAiChatReviewer } from "@/lib/ai/qa/reviewer-auth";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { adaptSchema, yupBoolean, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
@ -16,7 +16,7 @@ export const POST = createSmartRouteHandler({
|
||||
question: yupString().defined(),
|
||||
answer: yupString().defined(),
|
||||
publish: yupBoolean().defined(),
|
||||
requestId: yupString(),
|
||||
requestId: yupString().defined(),
|
||||
}).defined(),
|
||||
method: yupString().oneOf(["POST"]).defined(),
|
||||
}),
|
||||
@ -38,7 +38,7 @@ export const POST = createSmartRouteHandler({
|
||||
body.answer,
|
||||
body.publish,
|
||||
user.display_name ?? user.primary_email ?? user.id,
|
||||
body.requestId
|
||||
body.requestId,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@ -34,7 +34,7 @@ export const POST = createSmartRouteHandler({
|
||||
const token = getEnvVariable("STACK_MCP_LOG_TOKEN");
|
||||
const reviewer = user.display_name ?? user.primary_email ?? user.id;
|
||||
|
||||
await callReducerStrict("upsert_qa_from_call", [
|
||||
await callReducerStrict("upsert_qa_from_call_and_mark_reviewed", [
|
||||
token,
|
||||
body.correlationId,
|
||||
body.correctedQuestion,
|
||||
@ -42,7 +42,6 @@ export const POST = createSmartRouteHandler({
|
||||
body.publish,
|
||||
reviewer,
|
||||
]);
|
||||
await callReducerStrict("mark_human_reviewed", [token, body.correlationId, reviewer]);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@ -27,7 +27,7 @@ const endpoints = [
|
||||
},
|
||||
{
|
||||
path: "/api/latest/internal/mcp-review/add-manual",
|
||||
validBody: { question: "q", answer: "a", publish: false },
|
||||
validBody: { question: "q", answer: "a", publish: false, requestId: "test-req-id" },
|
||||
invalidBody: { question: "q" },
|
||||
},
|
||||
{
|
||||
|
||||
@ -77,7 +77,7 @@ describe.skipIf(!canRun)("private log tables and view gating", () => {
|
||||
const seed = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: seedMarker, answer: "a", publish: false },
|
||||
body: { question: seedMarker, answer: "a", publish: false, requestId: seedMarker },
|
||||
});
|
||||
expect(seed.status).toBe(200);
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ describe.skipIf(!canRun)("published_qa view projection", () => {
|
||||
const publish = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: markerQuestion, answer: markerAnswer, publish: true },
|
||||
body: { question: markerQuestion, answer: markerAnswer, publish: true, requestId: markerQuestion },
|
||||
});
|
||||
expect(publish.status).toBe(200);
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ describe.skipIf(!canRun)("published_qa visibility", () => {
|
||||
const add = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: marker, answer: "x", publish: false },
|
||||
body: { question: marker, answer: "x", publish: false, requestId: marker },
|
||||
});
|
||||
expect(add.status).toBe(200);
|
||||
|
||||
@ -63,7 +63,7 @@ describe.skipIf(!canRun)("published_qa visibility", () => {
|
||||
const add = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: marker, answer: "x", publish: true },
|
||||
body: { question: marker, answer: "x", publish: true, requestId: marker },
|
||||
});
|
||||
expect(add.status).toBe(200);
|
||||
expect(await publishedQaContains(marker)).toBe(true);
|
||||
@ -102,7 +102,7 @@ describe.skipIf(!canRun)("published_qa visibility", () => {
|
||||
const add = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: marker, answer: "x", publish: true },
|
||||
body: { question: marker, answer: "x", publish: true, requestId: marker },
|
||||
});
|
||||
expect(add.status).toBe(200);
|
||||
expect(await publishedQaContains(marker)).toBe(true);
|
||||
@ -137,7 +137,7 @@ describe.skipIf(!canRun)("published_qa visibility", () => {
|
||||
const add = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: marker, answer: "x", publish: true },
|
||||
body: { question: marker, answer: "x", publish: true, requestId: marker },
|
||||
});
|
||||
expect(add.status).toBe(200);
|
||||
expect(await publishedQaContains(marker)).toBe(true);
|
||||
|
||||
@ -61,7 +61,7 @@ describe.skipIf(!canRun)("qa_entries CRUD invariants", () => {
|
||||
const add = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: marker, answer: "a", publish: true },
|
||||
body: { question: marker, answer: "a", publish: true, requestId: marker },
|
||||
});
|
||||
expect(add.status).toBe(200);
|
||||
|
||||
@ -120,7 +120,7 @@ describe.skipIf(!canRun)("qa_entries CRUD invariants", () => {
|
||||
const add = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: marker, answer: "a", publish: true },
|
||||
body: { question: marker, answer: "a", publish: true, requestId: marker },
|
||||
});
|
||||
expect(add.status).toBe(200);
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ describe.skipIf(!canRun)("SpacetimeDB reducer auth", () => {
|
||||
const seedPublish = await niceBackendFetch("/api/latest/internal/mcp-review/add-manual", {
|
||||
method: "POST",
|
||||
accessType: "client",
|
||||
body: { question: seedMarker, answer: "a", publish: false },
|
||||
body: { question: seedMarker, answer: "a", publish: false, requestId: seedMarker },
|
||||
});
|
||||
expect(seedPublish.status).toBe(200);
|
||||
|
||||
@ -65,7 +65,7 @@ describe.skipIf(!canRun)("SpacetimeDB reducer auth", () => {
|
||||
name: "upsert_qa_from_call",
|
||||
args: [wrong, "corr", "q", "a", false, "reviewer"],
|
||||
},
|
||||
{ name: "add_manual_qa", args: [wrong, "q", "a", false, "reviewer", opt(null)] },
|
||||
{ name: "add_manual_qa", args: [wrong, "q", "a", false, "reviewer", "req-id"] },
|
||||
{ name: "delete_qa_entry", args: [wrong, 0n] },
|
||||
{ name: "update_qa_entry_with_publish", args: [wrong, 0n, "q", "a", false, "reviewer"] },
|
||||
{
|
||||
|
||||
@ -441,6 +441,68 @@ export const upsert_qa_from_call = spacetimedb.reducer(
|
||||
}
|
||||
);
|
||||
|
||||
export const upsert_qa_from_call_and_mark_reviewed = spacetimedb.reducer(
|
||||
{
|
||||
token: t.string(),
|
||||
correlationId: t.string(),
|
||||
question: t.string(),
|
||||
answer: t.string(),
|
||||
publish: t.bool(),
|
||||
reviewer: t.string(),
|
||||
},
|
||||
(ctx, args) => {
|
||||
if (args.token !== EXPECTED_LOG_TOKEN) {
|
||||
throw new SenderError('Invalid log token');
|
||||
}
|
||||
const callLogRow = ctx.db.mcpCallLog.correlationId.find(args.correlationId);
|
||||
if (callLogRow == null) {
|
||||
throw new SenderError('Call log not found for correlationId: ' + args.correlationId);
|
||||
}
|
||||
|
||||
let existing = null;
|
||||
for (const row of ctx.db.qaEntries.shard.filter(0)) {
|
||||
if (row.sourceMcpCorrelationId === args.correlationId) {
|
||||
existing = row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (existing != null) {
|
||||
ctx.db.qaEntries.id.update({
|
||||
...existing,
|
||||
question: args.question,
|
||||
answer: args.answer,
|
||||
lastEditedBy: args.reviewer,
|
||||
lastEditedAt: ctx.timestamp,
|
||||
published: args.publish,
|
||||
firstPublishedAt: args.publish ? (existing.firstPublishedAt ?? ctx.timestamp) : existing.firstPublishedAt,
|
||||
lastPublishedAt: args.publish ? ctx.timestamp : existing.lastPublishedAt,
|
||||
});
|
||||
} else {
|
||||
ctx.db.qaEntries.insert({
|
||||
id: 0n,
|
||||
shard: 0,
|
||||
sourceMcpCorrelationId: args.correlationId,
|
||||
requestId: undefined,
|
||||
question: args.question,
|
||||
answer: args.answer,
|
||||
createdBy: args.reviewer,
|
||||
createdAt: ctx.timestamp,
|
||||
lastEditedBy: args.reviewer,
|
||||
lastEditedAt: ctx.timestamp,
|
||||
published: args.publish,
|
||||
firstPublishedAt: args.publish ? ctx.timestamp : undefined,
|
||||
lastPublishedAt: args.publish ? ctx.timestamp : undefined,
|
||||
} as Parameters<typeof ctx.db.qaEntries.insert>[0]);
|
||||
}
|
||||
|
||||
ctx.db.mcpCallLog.id.update({
|
||||
...callLogRow,
|
||||
humanReviewedAt: ctx.timestamp,
|
||||
humanReviewedBy: args.reviewer,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export const add_manual_qa = spacetimedb.reducer(
|
||||
{
|
||||
token: t.string(),
|
||||
@ -448,13 +510,13 @@ export const add_manual_qa = spacetimedb.reducer(
|
||||
answer: t.string(),
|
||||
publish: t.bool(),
|
||||
createdBy: t.string(),
|
||||
requestId: t.string().optional(),
|
||||
requestId: t.string(),
|
||||
},
|
||||
(ctx, args) => {
|
||||
if (args.token !== EXPECTED_LOG_TOKEN) {
|
||||
throw new SenderError('Invalid log token');
|
||||
}
|
||||
if (args.requestId != null && args.requestId !== '') {
|
||||
if (args.requestId !== '') {
|
||||
for (const existing of ctx.db.qaEntries.iter()) {
|
||||
if (existing.requestId === args.requestId) return;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user