mirror of
https://github.com/we-promise/sure.git
synced 2026-09-03 13:51:29 +00:00
* feat(mcp): Add MCP budget update tool Adds an update_budget assistant/MCP function so AI assistants can write monthly budgets: total budgeted spending, expected income, and per-category allocations in one transactional call. - Month resolution and slug format mirror get_budget (YYYY-MM or MMM-YYYY, custom month start respected); targeting a valid month with no budget row bootstraps it via Budget.find_or_bootstrap, same as the budgets UI. - Category allocations accept an exact (case-insensitive) name or id and go through BudgetCategory#update_budgeted_spending!, so subcategory writes keep the parent total in sync. - All writes in one call share a transaction: an invalid category rolls back a totals change from the same call. - Family-scoped like the budgets UI; amounts validated non-negative. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(mcp): harden update_budget per review feedback - Extract shared month resolution into Assistant::Function::MonthResolvable so get_budget and update_budget can't drift on custom month starts - Run budget bootstrap inside the update transaction so a failed entry no longer leaves a newly created budget behind - Apply explicit parent amounts after subcategory syncs so results don't depend on the caller's array order - Reject non-finite amounts (NaN/Infinity) - Explain the synthetic Uncategorized bucket instead of a generic category-not-found error Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
72 lines
2.1 KiB
Ruby
72 lines
2.1 KiB
Ruby
module Assistant
|
|
Error = Class.new(StandardError)
|
|
|
|
REGISTRY = {
|
|
"builtin" => Assistant::Builtin,
|
|
"external" => Assistant::External
|
|
}.freeze
|
|
|
|
# Statement Vault + provenance tools, for users who opted into preview features
|
|
# in Settings -> Preferences. They back the wealth agent-harness workflow
|
|
# documented in docs/llm-guides/wealth-agent-harness.md.
|
|
PREVIEW_FUNCTION_CLASSES = [
|
|
Function::UploadAccountStatement,
|
|
Function::ListAccountStatements,
|
|
Function::GetAccountStatement,
|
|
Function::GetStatementCoverage,
|
|
Function::RecordValuation
|
|
].freeze
|
|
|
|
class << self
|
|
def for_chat(chat)
|
|
implementation_for(chat).for_chat(chat)
|
|
end
|
|
|
|
def config_for(chat)
|
|
raise Error, "chat is required" if chat.blank?
|
|
Assistant::Builtin.config_for(chat)
|
|
end
|
|
|
|
def available_types
|
|
REGISTRY.keys
|
|
end
|
|
|
|
# The single registry behind both the builtin chat and the /mcp endpoint's
|
|
# tools/list — a function class added here is immediately callable by an
|
|
# external agent, so pass the user to keep preview tools out of the default
|
|
# surface.
|
|
def function_classes(user = nil)
|
|
classes = [
|
|
Function::GetTransactions,
|
|
Function::GetAccounts,
|
|
Function::GetHoldings,
|
|
Function::GetBalanceSheet,
|
|
Function::GetIncomeStatement,
|
|
Function::GetBudget,
|
|
Function::ImportBankStatement,
|
|
Function::SearchFamilyFiles,
|
|
Function::CreateGoal,
|
|
Function::GetTags,
|
|
Function::CreateTag,
|
|
Function::UpdateTag,
|
|
Function::GetCategories,
|
|
Function::CreateCategory,
|
|
Function::UpdateCategory,
|
|
Function::UpdateTransaction,
|
|
Function::UpdateBudget
|
|
]
|
|
|
|
classes += PREVIEW_FUNCTION_CLASSES if user&.preview_features_enabled?
|
|
classes
|
|
end
|
|
|
|
private
|
|
|
|
def implementation_for(chat)
|
|
raise Error, "chat is required" if chat.blank?
|
|
type = ENV["ASSISTANT_TYPE"].presence || chat.user&.family&.assistant_type.presence || "builtin"
|
|
REGISTRY.fetch(type) { REGISTRY["builtin"] }
|
|
end
|
|
end
|
|
end
|