Part 3 of #2185. A user with several imported years concluded the assistant "only reads the period I am standing in". Nothing restricted it: the report tools defaulted to the most recent fiscal period when no period_id was given and then rejected any from_date/to_date/as_of_date outside it, and neither the snapshot nor the chat identity block told the model which years existed or how to address them. - extensions/general/mcp-server/server.ts: resolveReportPeriod takes a date hint; without period_id, a date in the call resolves the fiscal period that contains it (findFiscalPeriodContaining, company-scoped), and a date no period covers fails with the company's span instead of the latest year's bounds. Income statement (from_date or to_date), balance sheet (as_of_date) and dimension P&L (to_date) use it. The range guard is unchanged. No schema change: tools/list sits at its token ceiling. - lib/agent/fiscal-years.ts: one query and one line, "Räkenskapsår (senaste först): ... period_id=<uuid> (senaste|avslutat)", plus the rule on addressing an earlier year, shared by the single-call snapshot and the streaming chat's always-on identity block. - lib/agent/intents/shared-rules.ts and TOOL_RULES: pass that year's period_id, one call per year, and say which räkenskapsår the answer covers. Claude-Session: https://claude.ai/code/session_0179bdetHyofL6ATfQxB5wP5 Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
69 lines
2.7 KiB
TypeScript
69 lines
2.7 KiB
TypeScript
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
|
|
/**
|
|
* The company's räkenskapsår as one prompt line, so the assistant knows which
|
|
* years exist and how to address them. Without it the model only ever saw
|
|
* the report tools' "default: most recent" and read a multi-year ledger as a
|
|
* single-year one (#2185): a question about 2023 had no period_id to pass
|
|
* and no hint that one existed.
|
|
*
|
|
* Shared by the single-call assistant snapshot (lib/agent/ask/snapshot.ts)
|
|
* and the streaming chat's identity block (lib/agent/chat/system-prompt.ts),
|
|
* so both surfaces carry the same inventory from one query. Company-scoped
|
|
* and best-effort: a failing query yields an empty list, never an error.
|
|
*/
|
|
|
|
export interface FiscalYearInventoryRow {
|
|
id: string
|
|
name: string
|
|
period_start: string
|
|
period_end: string
|
|
is_closed: boolean
|
|
}
|
|
|
|
/** Newest first. Enough for a decade of imports without bloating the prompt. */
|
|
export const FISCAL_YEAR_INVENTORY_CAP = 8
|
|
|
|
export async function loadFiscalYearInventory(
|
|
supabase: SupabaseClient,
|
|
companyId: string,
|
|
): Promise<FiscalYearInventoryRow[]> {
|
|
try {
|
|
const { data } = await supabase
|
|
.from('fiscal_periods')
|
|
.select('id, name, period_start, period_end, is_closed')
|
|
.eq('company_id', companyId)
|
|
.order('period_start', { ascending: false })
|
|
.limit(FISCAL_YEAR_INVENTORY_CAP)
|
|
return ((data ?? []) as FiscalYearInventoryRow[]).filter(
|
|
(row) => typeof row?.id === 'string' && typeof row.period_start === 'string',
|
|
)
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* "Räkenskapsår (senaste först): 2026-01-01..2026-12-31 period_id=<uuid>
|
|
* (senaste); 2025-01-01..2025-12-31 period_id=<uuid> (avslutat)." Null when
|
|
* the company has no periods, so the caller can drop the line.
|
|
*/
|
|
export function renderFiscalYearInventory(rows: FiscalYearInventoryRow[]): string | null {
|
|
if (rows.length === 0) return null
|
|
const items = rows.map((row, index) => {
|
|
const marks: string[] = []
|
|
if (index === 0) marks.push('senaste')
|
|
if (row.is_closed) marks.push('avslutat')
|
|
const suffix = marks.length > 0 ? ` (${marks.join(', ')})` : ''
|
|
return `${row.period_start}..${row.period_end} period_id=${row.id}${suffix}`
|
|
})
|
|
return `Räkenskapsår (senaste först): ${items.join('; ')}.`
|
|
}
|
|
|
|
/**
|
|
* The rule that goes with the inventory: how to ask a report tool about an
|
|
* earlier year, and to say which year an answer covers.
|
|
*/
|
|
export const FISCAL_YEAR_RULE =
|
|
'Frågor om ett tidigare räkenskapsår: skicka det årets period_id till rapportverktygen (resultatrapport, balansrapport, KPI, huvudbok, saldobalans); utan period_id läser de det senaste året. Säg alltid vilket räkenskapsår svaret gäller.'
|