Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ design-docs/
deploy-scripts/
test-data-loader/
scripts/
docs/esrp/*

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
Expand Down
37 changes: 0 additions & 37 deletions docs/desktop-portable.md

This file was deleted.

66 changes: 0 additions & 66 deletions loops/model-evaluation/plan.md

This file was deleted.

15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
"private": true,
"resolutions": {
"lodash": "^4.18.1",
"vite": "^7.3.3",
"dompurify": "^3.4.2",
"vite": "^7.3.5",
"dompurify": "^3.4.13",
"postcss": "^8.5.23",
"esbuild": "^0.28.1",
"tmp": "^0.2.6",
"markdown-it": "^14.3.0",
"linkify-it": "^5.0.2",
"undici": "^7.29.0",
Expand Down Expand Up @@ -43,14 +46,14 @@
"canvas": "^3.2.1",
"chart.js": "^4.5.1",
"d3": "^7.3.0",
"dompurify": "^3.4.0",
"echarts": "^6.0.0",
"dompurify": "^3.4.13",
"echarts": "^6.1.0",
"exceljs": "^4.4.0",
"flint-chart": ">=0.5.0",
"html2canvas": "^1.4.1",
"i18next": "^26.0.1",
"i18next-browser-languagedetector": "^8.2.1",
"js-yaml": "^4.1.1",
"js-yaml": "^4.3.1",
"katex": "^0.16.22",
"localforage": "^1.10.0",
"lodash": "^4.18.1",
Expand Down Expand Up @@ -130,7 +133,7 @@
"jsdom": "^29.0.1",
"sass": "^1.102.0",
"typescript-eslint": "^8.65.0",
"vite": "^7.3.3",
"vite": "^7.3.5",
"vitest": "^4.1.0"
}
}
33 changes: 23 additions & 10 deletions py-src/data_formulator/agents/agent_data_loading_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,11 +789,11 @@ def _build_connector_summary_block(
*,
max_total_chars: int = 1200,
) -> str:
"""Render a compact directory of cached connector catalogs.
"""Render a compact directory of currently loadable connectors.

Only shows source IDs with table counts (and folder counts when the
catalog is hierarchical). The agent is expected to call ``list_data``
for full inventory.
Shows connected sources even before their catalog has been cached. Retained
catalogs for disconnected sources stay on disk but are not agent-visible.
The agent is expected to call ``list_data`` for full inventory.
Strictly hard-capped at ``max_total_chars``.
"""
if not user_home:
Expand All @@ -807,32 +807,45 @@ def _build_connector_summary_block(
return " none"

try:
source_ids = list_cached_sources(user_home)
from data_formulator.data_connector import (
connector_is_available,
list_available_connector_ids,
)
cached_source_ids = set(list_cached_sources(user_home))
available_source_ids = set(list_available_connector_ids())
source_ids = sorted(
source_id
for source_id in cached_source_ids | available_source_ids
if connector_is_available(source_id) is not False
)
except Exception:
logger.debug("connector summary: list_cached_sources failed", exc_info=True)
logger.debug("connector summary: source inventory failed", exc_info=True)
return " none"

if not source_ids:
return " none"

user_home_path = Path(user_home)
lines: list[str] = []
for sid in sorted(source_ids):
for sid in source_ids:
try:
tables = load_catalog(user_home_path, sid) or []
except Exception:
logger.debug("connector summary: load_catalog failed for %s", sid, exc_info=True)
tables = []
n, k = _summarize_catalog_shape(tables)
if n == 0:
lines.append(f"- {sid}: 0 tables cached")
status = "connected, catalog not cached" if sid in available_source_ids else "0 tables cached"
lines.append(f"- {sid}: {status}")
elif k > 0:
availability = "connected" if sid in available_source_ids else "catalog available"
lines.append(
f"- {sid}: {n} table{'s' if n != 1 else ''} "
f"- {sid}: {availability}; {n} table{'s' if n != 1 else ''} "
f"across {k} folder{'s' if k != 1 else ''}"
)
else:
lines.append(f"- {sid}: {n} table{'s' if n != 1 else ''}")
availability = "connected" if sid in available_source_ids else "catalog available"
lines.append(f"- {sid}: {availability}; {n} table{'s' if n != 1 else ''}")

lines.append(
" (call list_data() for sources, list_data(source_id, ...) to drill, "
Expand Down
9 changes: 4 additions & 5 deletions py-src/data_formulator/agents/agent_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,8 @@ def generate_data_summary(
Use WorkspaceWithTempData context manager to mount temp tables to workspace.

When ``primary_tables`` is provided, the output is structured into tiered sections:
- **[PRIMARY TABLE]** / **[PRIMARY TABLES]**: Full detail for the tables the user is focused on.
- **[OTHER AVAILABLE TABLES]**: Full detail for the remaining tables.
- **[PRIMARY ANALYSIS INPUTS]**: Full detail for the input tables the user is focused on.
- **[OTHER ANALYSIS INPUTS]**: Full detail for the remaining input tables.
Sections are omitted when empty.

Args:
Expand Down Expand Up @@ -737,10 +737,9 @@ def assemble_table_summary(table, idx):

sections = []
if primary_parts:
header = "[PRIMARY TABLE]" if len(primary_parts) == 1 else "[PRIMARY TABLES]"
sections.append(header + "\n\n" + separator.join(primary_parts))
sections.append("[PRIMARY ANALYSIS INPUTS]\n\n" + separator.join(primary_parts))
if other_parts:
sections.append("[OTHER AVAILABLE TABLES]\n\n" + separator.join(other_parts))
sections.append("[OTHER ANALYSIS INPUTS]\n\n" + separator.join(other_parts))
return "\n\n".join(sections)

# Join with visual separators (no tiering)
Expand Down
13 changes: 8 additions & 5 deletions py-src/data_formulator/agents/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def build_lightweight_table_context(
"""Build compact table context with schema, metadata, value samples, and rows.

When ``primary_tables`` is provided, tables are grouped into
[PRIMARY TABLE(S)] and [OTHER AVAILABLE TABLES] sections.
[PRIMARY ANALYSIS INPUTS] and [OTHER ANALYSIS INPUTS] sections.
"""
table_desc_cache, col_desc_cache, import_opts_cache = _get_workspace_metadata_lookups(workspace)
table_extra_cache: dict[str, list[str]] = {}
Expand Down Expand Up @@ -263,7 +263,7 @@ def _table_section(table: dict[str, Any]) -> str:
return _client_schema_section(table, label)

load_hint = (
"\nThe tables above are the data already loaded into this workspace, and the "
"\nThe analysis input tables above are already materialized and are the "
"only data you can read directly. Anything not listed here has not been loaded "
"yet: find it in a connected source and propose loading it before relying on it.\n"
"To load a table in code: pd.read_parquet('file.parquet') or "
Expand All @@ -278,12 +278,11 @@ def _table_section(table: dict[str, Any]) -> str:

sections = []
if primary_tables_list:
header = "[PRIMARY TABLE]" if len(primary_tables_list) == 1 else "[PRIMARY TABLES]"
primary_parts = [_table_section(t) for t in primary_tables_list]
sections.append(header + "\n\n" + "\n\n".join(primary_parts))
sections.append("[PRIMARY ANALYSIS INPUTS]\n\n" + "\n\n".join(primary_parts))
if other_tables_list:
other_parts = [_table_section(t) for t in other_tables_list]
sections.append("[OTHER AVAILABLE TABLES]\n\n" + "\n\n".join(other_parts))
sections.append("[OTHER ANALYSIS INPUTS]\n\n" + "\n\n".join(other_parts))
return "\n\n".join(sections) + "\n" + load_hint

sections = [_table_section(table) for table in input_tables]
Expand Down Expand Up @@ -375,6 +374,10 @@ def handle_read_catalog_metadata(
if not user_home:
return "Cannot read catalog metadata: user home not available."

from data_formulator.datalake.connector_preferences import connector_is_enabled
if not connector_is_enabled(user_home, source_id):
return f"Source '{source_id}' is disconnected."

# Surface zero-config admin connectors (e.g. sample_datasets) on first use.
ensure_no_auth_catalogs_cached(user_home)

Expand Down
Loading