feat: add guarded savings agent tools

This commit is contained in:
Matthias
2026-06-23 21:13:02 +02:00
parent 6e687dc9b5
commit b7dae31fe1
22 changed files with 3510 additions and 73 deletions

View File

@@ -24,6 +24,51 @@ const chatCitation = v.object({
marker: v.string(),
sourceId: v.string(),
});
const agentActionPlanStatus = v.union(
v.literal("pending"),
v.literal("applied"),
v.literal("dismissed"),
v.literal("expired"),
);
const agentActionPlanKind = v.union(
v.literal("bulk_recategory"),
v.literal("category_changes"),
);
const agentActionPlanOperation = v.union(
v.object({
type: v.literal("set_transaction_category"),
transactionId: v.id("transactions"),
fromCategoryId: v.optional(v.id("categories")),
toCategoryId: v.id("categories"),
}),
v.object({
type: v.literal("create_category"),
name: v.string(),
kind: categoryKind,
block: v.optional(expenseBlock),
color: v.string(),
icon: v.optional(v.string()),
sortOrder: v.number(),
}),
v.object({
type: v.literal("update_category"),
categoryId: v.id("categories"),
name: v.optional(v.string()),
kind: v.optional(categoryKind),
block: v.optional(expenseBlock),
color: v.optional(v.string()),
icon: v.optional(v.string()),
sortOrder: v.optional(v.number()),
}),
);
const agentActionPlanPreviewRow = v.object({
date: v.optional(v.string()),
description: v.string(),
amount: v.optional(v.number()),
currentCategoryName: v.optional(v.string()),
targetCategoryName: v.optional(v.string()),
action: v.optional(v.string()),
});
export default defineSchema({
...authTables,
@@ -41,6 +86,22 @@ export default defineSchema({
.index("by_user", ["userId"])
.index("by_user_external", ["userId", "externalId"]),
accountBalances: defineTable({
userId: v.id("users"),
accountId: v.id("accounts"),
externalId: v.string(),
provider: v.union(v.literal("comdirect"), v.literal("fints")),
balance: v.number(),
currency: v.string(),
asOf: v.optional(v.string()),
fetchedAt: v.number(),
status: v.union(v.literal("fresh"), v.literal("stale"), v.literal("error")),
errorMessage: v.optional(v.string()),
})
.index("by_user", ["userId"])
.index("by_user_account", ["userId", "accountId"])
.index("by_user_provider_fetched", ["userId", "provider", "fetchedAt"]),
categories: defineTable({
userId: v.id("users"),
name: v.string(),
@@ -214,4 +275,20 @@ export default defineSchema({
sources: v.optional(v.array(chatSource)),
citations: v.optional(v.array(chatCitation)),
}).index("by_user_session_created", ["userId", "sessionId", "createdAt"]),
agentActionPlans: defineTable({
userId: v.id("users"),
sessionId: v.id("chatSessions"),
kind: agentActionPlanKind,
status: agentActionPlanStatus,
summary: v.string(),
affectedCount: v.number(),
createdAt: v.number(),
expiresAt: v.number(),
operations: v.array(agentActionPlanOperation),
previewRows: v.array(agentActionPlanPreviewRow),
resultSummary: v.optional(v.string()),
})
.index("by_user_session_status_created", ["userId", "sessionId", "status", "createdAt"])
.index("by_user_status_expires", ["userId", "status", "expiresAt"]),
});