- ngOnInit restores conversation from sessionStorage on mount
- saveHistory() persists every message exchange automatically
- clearHistory() resets to welcome message and wipes stored history
- Clear button added to panel header (small, subtle, matches dark theme)
- welcomeMessage getter adapts copy based on enableRealEstate flag
Made-with: Cursor
- ngOnInit restores conversation from sessionStorage on mount
- saveHistory() persists every message exchange automatically
- clearHistory() resets to welcome message and wipes stored history
- Clear button added to panel header (small, subtle, matches dark theme)
- welcomeMessage getter adapts copy based on enableRealEstate flag
Made-with: Cursor
- test_search_listings_bedroom_filter: min_beds=3 returns only 3+ bed
listings and records the filter in result.filters_applied.
- test_search_listings_price_filter: max_price=400000 excludes listings
above threshold and records filter in result.filters_applied.
- test_structured_error_code: all error paths return nested
{code, message} dict with a REAL_ESTATE_* code.
- Updated test_feature_flag_disabled: assert nested error dict with
REAL_ESTATE_FEATURE_DISABLED code.
- Updated test_unknown_location_graceful_error: assert nested error
dict with REAL_ESTATE_PROVIDER_UNAVAILABLE code.
All 8 tests pass in < 1s.
Made-with: Cursor
- test_search_listings_bedroom_filter: min_beds=3 returns only 3+ bed
listings and records the filter in result.filters_applied.
- test_search_listings_price_filter: max_price=400000 excludes listings
above threshold and records filter in result.filters_applied.
- test_structured_error_code: all error paths return nested
{code, message} dict with a REAL_ESTATE_* code.
- Updated test_feature_flag_disabled: assert nested error dict with
REAL_ESTATE_FEATURE_DISABLED code.
- Updated test_unknown_location_graceful_error: assert nested error
dict with REAL_ESTATE_PROVIDER_UNAVAILABLE code.
All 8 tests pass in < 1s.
Made-with: Cursor
- main.py: add GET /real-estate/log endpoint (feature-flag gated).
Returns total_invocations, success_count, failure_count, and
last 50 log entries from real_estate._invocation_log.
Returns 404 when ENABLE_REAL_ESTATE is not true.
Made-with: Cursor
- main.py: add GET /real-estate/log endpoint (feature-flag gated).
Returns total_invocations, success_count, failure_count, and
last 50 log entries from real_estate._invocation_log.
Returns 404 when ENABLE_REAL_ESTATE is not true.
Made-with: Cursor
- search_listings(): add min_beds and max_price optional filter params
with per-field filtering before max_results cap.
filters_applied dict included in result for transparency.
Cache key incorporates filter values.
- All error returns now use nested {code, message} format:
REAL_ESTATE_FEATURE_DISABLED, REAL_ESTATE_PROVIDER_UNAVAILABLE.
- Add _invocation_log + _log_invocation() module-level observability:
records timestamp, function, query (80-char truncated), duration_ms,
success. Bounded to 500 entries. Exposed via get_invocation_log().
- _log_invocation() called in all 4 public functions (both success
and failure paths, including cache hits).
Made-with: Cursor
- search_listings(): add min_beds and max_price optional filter params
with per-field filtering before max_results cap.
filters_applied dict included in result for transparency.
Cache key incorporates filter values.
- All error returns now use nested {code, message} format:
REAL_ESTATE_FEATURE_DISABLED, REAL_ESTATE_PROVIDER_UNAVAILABLE.
- Add _invocation_log + _log_invocation() module-level observability:
records timestamp, function, query (80-char truncated), duration_ms,
success. Bounded to 500 entries. Exposed via get_invocation_log().
- _log_invocation() called in all 4 public functions (both success
and failure paths, including cache hits).
Made-with: Cursor
- graph.py: import real_estate functions (get_neighborhood_snapshot,
search_listings, compare_neighborhoods, is_real_estate_enabled).
- classify_node: detect real estate keywords → route to
real_estate_snapshot | real_estate_search | real_estate_compare.
Detection is fully guarded by is_real_estate_enabled() — when flag
is off, this block is never entered and existing routing is unchanged.
- tools_node: 3 new elif branches for real estate query types.
All append-only; no existing branches modified.
- Added _extract_real_estate_location() and _extract_two_locations()
helpers (new functions, no changes to existing helpers).
Made-with: Cursor
- graph.py: import real_estate functions (get_neighborhood_snapshot,
search_listings, compare_neighborhoods, is_real_estate_enabled).
- classify_node: detect real estate keywords → route to
real_estate_snapshot | real_estate_search | real_estate_compare.
Detection is fully guarded by is_real_estate_enabled() — when flag
is off, this block is never entered and existing routing is unchanged.
- tools_node: 3 new elif branches for real estate query types.
All append-only; no existing branches modified.
- Added _extract_real_estate_location() and _extract_two_locations()
helpers (new functions, no changes to existing helpers).
Made-with: Cursor
- New tools/real_estate.py: MockProvider with realistic 2024 data for
10 US cities. TTL in-memory cache (5-min). Feature flag:
ENABLE_REAL_ESTATE=true/false — false = zero behavior change.
- tools/__init__.py: 3 new TOOL_REGISTRY entries (append-only).
- README.md: Real Estate demo section with 2-minute run instructions.
Made-with: Cursor
- New tools/real_estate.py: MockProvider with realistic 2024 data for
10 US cities. TTL in-memory cache (5-min). Feature flag:
ENABLE_REAL_ESTATE=true/false — false = zero behavior change.
- tools/__init__.py: 3 new TOOL_REGISTRY entries (append-only).
- README.md: Real Estate demo section with 2-minute run instructions.
Made-with: Cursor
- eval runner: add retry logic (2 attempts) for transient connection drops
- gs-001: accept 'percent' as well as '%' (LLM formatting variance)
- gs-002: use must_contain_one_of for ticker/company name variance
- gs-008/sc-014: fix expected_tools for conditionally-triggered compliance
- graph.py: route 'health check'/'full report' queries to compliance path
so compliance_check always runs for full portfolio report requests
Co-authored-by: Cursor <cursoragent@cursor.com>
- eval runner: add retry logic (2 attempts) for transient connection drops
- gs-001: accept 'percent' as well as '%' (LLM formatting variance)
- gs-002: use must_contain_one_of for ticker/company name variance
- gs-008/sc-014: fix expected_tools for conditionally-triggered compliance
- graph.py: route 'health check'/'full report' queries to compliance path
so compliance_check always runs for full portfolio report requests
Co-authored-by: Cursor <cursoragent@cursor.com>
Source tags [tool_result_id] were appearing after every individual figure,
making responses unreadable. Rules 1 and 10 in SYSTEM_PROMPT and the
format_node user prompt now enforce one citation per sentence placed at
the end, not inline after each value.
Co-authored-by: Cursor <cursoragent@cursor.com>
Source tags [tool_result_id] were appearing after every individual figure,
making responses unreadable. Rules 1 and 10 in SYSTEM_PROMPT and the
format_node user prompt now enforce one citation per sentence placed at
the end, not inline after each value.
Co-authored-by: Cursor <cursoragent@cursor.com>
Raised bottom from 1.5rem to 5.5rem and reduced size slightly so the
Ask AI button no longer overlaps the Add Account / Add Transaction FABs
that Ghostfolio renders at the bottom-right of the screen.
Co-authored-by: Cursor <cursoragent@cursor.com>
When the agent returns an empty-portfolio response (e.g. after a new
Google OAuth sign-in), a blue banner appears offering to load 18 demo
activities. Clicking 'Load demo data' calls POST /agent/seed with the
user's own bearer token so the seeded data belongs to their account.
Also adds the /seed URL construction in the component constructor.
Co-authored-by: Cursor <cursoragent@cursor.com>
Injects TokenStorageService and passes the active session token in
every /agent/chat request body as bearer_token. The agent now serves
each user's own portfolio data. Unauthenticated visitors still get the
shared demo data via the agent's env-var fallback.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(lib): resolve typescript errors
* feat(lib): migrate to takeUntilDestroyed
* fix(lib): resolve type errors
* feat(lib): implement output signal
* feat(lib): clean up variables
* fix(lib): resolve input is deprecated
* feat(lib): implement input signal on placeholder
* feat(lib): implement input signal on isLoading
* fix(lib): add type annotations for date adapter
* fix(lib): handle form value possibly null
* fix(lint): use arrow fn for validators
* fix(lib): accounts table typings
* fix(lib): remove unsubscribeSubject due to lack of observable
* fix(lib): remove validators variable
* feat(lib): implement inject functions
* feat(lib): make locale an input signal
* feat(lib): make showActions an input signal
* feat(lib): make accountId an input signal
* feat(lib): make accountCurrency an input signal
* feat(lib): make accountBalances an input signal
* feat(lib): make sort a viewChild signal
* feat(lib): implement isNil