Datasource Connectors
Guide the user through loading data from any common source into a working dataset.
This module is a decision framework, not a library. It tells the LLM what to ask,
what to watch for, and how to handle each format's quirks.
When to Use
- The brief names a data source that is not yet loaded
- The user says "the data is in X" where X is a file, database, or API
- The orchestrator's plan includes an Ingest step
When to Skip
- Data is already loaded (inline table, prior step output, user pasted it)
- The brief says "data is pre-loaded" or "use this dataframe"
Connector Selection
Ask the user what format the data is in, or infer from the path/URL:
| Signal |
Connector |
.csv, .tsv, .txt (tabular) |
CSV |
.json, .jsonl, .ndjson |
JSON |
http://, https:// + returns JSON/XML |
REST API |
Connection string, .sql, database name |
SQL |
.xlsx, .xls |
Excel |
.parquet, .arrow |
Parquet |
If ambiguous, ask. Do not guess the format.
CSV / TSV
What to ask
- Does the file have a header row? (default: yes)
- What is the delimiter? (auto-detect: comma, tab, semicolon, pipe)
- What is the encoding? (default: UTF-8; watch for: Latin-1, Windows-1252)
Quirks to handle
| Problem |
Detection |
Fix |
| Wrong delimiter |
First row has one column |
Try tab, semicolon, pipe |
| Encoding garbled |
Non-ASCII chars show as ? or é |
Re-read as Latin-1 or Windows-1252 |
| Trailing commas |
Row has one extra empty column |
Strip trailing delimiter |
| Quoted fields with commas |
Standard CSV; most parsers handle it |
Use RFC 4180 compliant parser |
| Mixed line endings |
\r\n and \n in same file |
Normalize to \n |
| BOM marker |
\xEF\xBB\xBF at file start |
Strip or let parser handle |
Output
A table with typed columns. Report: row count, column count, detected delimiter,
detected encoding.
JSON / JSONL
What to ask
- Is it a single JSON object, an array, or newline-delimited (JSONL)?
- What path holds the data? (e.g.,
data.results[], root array)
Quirks to handle
| Problem |
Detection |
Fix |
| Nested objects |
Column values are objects, not scalars |
Flatten with dot notation (address.city) |
| Mixed types in array |
Some items have extra/missing keys |
Union all keys; fill missing with null |
| Large file (> 100MB) |
Slow to parse |
Stream with JSONL or chunk |
| Date strings |
ISO 8601 or Unix timestamps |
Parse to date; state the format detected |
Output
A flat table. Nested objects flattened to dot-notation columns. Report: record
count, nesting depth, keys found.
REST API
What to ask
- What is the endpoint URL?
- What authentication is needed? (none, API key, OAuth, bearer token)
- Does it paginate? (offset, cursor, link header, or single page)
- What response path holds the data? (e.g.,
results[])
Authentication patterns
| Method |
How to use |
Security |
| API key in header |
Authorization: Api-Key <key> or custom header |
Never log the key |
| Bearer token |
Authorization: Bearer <token> |
Store in env var or secret |
| OAuth 2.0 |
Client credentials or authorization code flow |
Use refresh tokens |
| No auth |
Public API |
Still rate-limit respectfully |
Never hardcode credentials. Use environment variables or secret storage.
Pagination patterns
| Pattern |
Detection |
Handling |
| Offset |
?offset=0&limit=100 |
Increment offset until empty page |
| Cursor |
Response has next_cursor field |
Pass cursor to next request |
| Link header |
Link: <url>; rel="next" |
Follow rel="next" until absent |
| Page number |
?page=1&per_page=50 |
Increment page until empty |
Set a maximum page limit (default: 100 pages) to prevent runaway loops.
Retry and timeout
| Rule |
Value |
| Timeout per request |
30 seconds |
| Retries on 429/5xx |
3 with exponential backoff (1s, 2s, 4s) |
| Retries on network error |
2 |
| Never retry |
400, 401, 403, 404 (client errors are not transient) |
Output
A flat table from all pages combined. Report: total records, pages fetched,
any errors skipped.
SQL
What to ask
- What database engine? (PostgreSQL, SQL Server, MySQL, SQLite)
- Connection string or host/port/database?
- What table or query?
Security rules
| Rule |
Reason |
| Always use parameterized queries |
Prevents SQL injection |
| Never interpolate user input into SQL |
Even for table names; use allowlists |
| Read-only connection |
The pipeline only reads; never write |
| Credentials in env vars |
Never in code, never in logs |
Query patterns
-- Simple table read
SELECT * FROM schema.table_name LIMIT 1000;
-- Filtered read (parameterized)
SELECT * FROM sales WHERE region = @region AND date >= @start_date;
-- Aggregated read (push aggregation to the database when possible)
SELECT region, month, SUM(revenue) AS revenue
FROM sales
GROUP BY region, month;
Push aggregation and filtering to the database when possible. Pulling raw data
and aggregating in the LLM wastes tokens and is slower.
Output
A table. Report: row count, column count, query execution time, database engine.
Excel
What to ask
- Which sheet? (default: first sheet)
- Does the data start at A1 or is there a header region to skip?
- Are there named ranges?
Quirks to handle
| Problem |
Detection |
Fix |
| Multiple sheets |
Workbook has > 1 sheet |
Ask which sheet; default to first |
| Header not in row 1 |
First rows are title/metadata |
Ask for header row number |
| Merged cells |
Values span multiple rows/columns |
Unmerge and fill down |
| Formulas |
Cells contain formulas, not values |
Read values, not formulas |
| Mixed types in column |
Numbers and text in same column |
Coerce to string; flag for data-preparation |
| Date serial numbers |
Dates stored as integers (e.g., 45678) |
Convert using Excel epoch (1899-12-30) |
Output
A table from the specified sheet and range. Report: sheet name, row count,
column count, any merged cells detected.
Parquet / Arrow
What to ask
- Path to the file or directory (partitioned datasets use directories)
Advantages
Parquet is self-describing: schema, types, and encoding are embedded. No
delimiter guessing, no encoding issues, no header detection.
Quirks to handle
| Problem |
Detection |
Fix |
| Partitioned directory |
Path is a directory with part-*.parquet files |
Read all partitions |
| Nested columns (struct/list) |
Schema shows complex types |
Flatten or ask user which fields |
| Large file |
> 1M rows |
Sample or filter before loading all |
Output
A typed table. Report: row count, column count, schema summary (types from
the Parquet metadata).
Error Handling (all connectors)
| Situation |
Action |
| File not found |
Report the exact path tried. Ask user to verify. |
| Permission denied |
Report the error. Do not retry. Ask user to fix permissions. |
| Empty dataset (0 rows) |
Report it. Push back: "file exists but has no data rows." |
| Partial data (truncated) |
Report row count. Ask if this is expected. |
| Unsupported format |
State what was detected. Ask user for the correct format. |
Never fail silently. Every error must produce a specific, actionable message.
Output Contract
Pass to the next module (data-preparation):
- The loaded dataset (or a reference to it)
- A one-line summary: format, row count, column count, source path
- Any warnings (encoding fallback, partial data, skipped errors)
1---2name: datasource-connectors3description: Ingestion patterns for CSV, JSON, REST API, SQL, Excel, and Parquet -- guides an LLM through loading data from any common source4---56# Datasource Connectors78Guide the user through loading data from any common source into a working dataset.9This module is a decision framework, not a library. It tells the LLM what to ask,10what to watch for, and how to handle each format's quirks.1112## When to Use1314- The brief names a data source that is not yet loaded15- The user says "the data is in X" where X is a file, database, or API16- The orchestrator's plan includes an Ingest step1718## When to Skip1920- Data is already loaded (inline table, prior step output, user pasted it)21- The brief says "data is pre-loaded" or "use this dataframe"2223## Connector Selection2425Ask the user what format the data is in, or infer from the path/URL:2627| Signal | Connector |28| --- | --- |29| `.csv`, `.tsv`, `.txt` (tabular) | CSV |30| `.json`, `.jsonl`, `.ndjson` | JSON |31| `http://`, `https://` + returns JSON/XML | REST API |32| Connection string, `.sql`, database name | SQL |33| `.xlsx`, `.xls` | Excel |34| `.parquet`, `.arrow` | Parquet |3536If ambiguous, ask. Do not guess the format.3738## CSV / TSV3940### What to ask4142- Does the file have a header row? (default: yes)43- What is the delimiter? (auto-detect: comma, tab, semicolon, pipe)44- What is the encoding? (default: UTF-8; watch for: Latin-1, Windows-1252)4546### Quirks to handle4748| Problem | Detection | Fix |49| --- | --- | --- |50| Wrong delimiter | First row has one column | Try tab, semicolon, pipe |51| Encoding garbled | Non-ASCII chars show as `?` or `é` | Re-read as Latin-1 or Windows-1252 |52| Trailing commas | Row has one extra empty column | Strip trailing delimiter |53| Quoted fields with commas | Standard CSV; most parsers handle it | Use RFC 4180 compliant parser |54| Mixed line endings | `\r\n` and `\n` in same file | Normalize to `\n` |55| BOM marker | `\xEF\xBB\xBF` at file start | Strip or let parser handle |5657### Output5859A table with typed columns. Report: row count, column count, detected delimiter,60detected encoding.6162## JSON / JSONL6364### What to ask6566- Is it a single JSON object, an array, or newline-delimited (JSONL)?67- What path holds the data? (e.g., `data.results[]`, root array)6869### Quirks to handle7071| Problem | Detection | Fix |72| --- | --- | --- |73| Nested objects | Column values are objects, not scalars | Flatten with dot notation (`address.city`) |74| Mixed types in array | Some items have extra/missing keys | Union all keys; fill missing with null |75| Large file (> 100MB) | Slow to parse | Stream with JSONL or chunk |76| Date strings | ISO 8601 or Unix timestamps | Parse to date; state the format detected |7778### Output7980A flat table. Nested objects flattened to dot-notation columns. Report: record81count, nesting depth, keys found.8283## REST API8485### What to ask86871. What is the endpoint URL?882. What authentication is needed? (none, API key, OAuth, bearer token)893. Does it paginate? (offset, cursor, link header, or single page)904. What response path holds the data? (e.g., `results[]`)9192### Authentication patterns9394| Method | How to use | Security |95| --- | --- | --- |96| **API key in header** | `Authorization: Api-Key <key>` or custom header | Never log the key |97| **Bearer token** | `Authorization: Bearer <token>` | Store in env var or secret |98| **OAuth 2.0** | Client credentials or authorization code flow | Use refresh tokens |99| **No auth** | Public API | Still rate-limit respectfully |100101Never hardcode credentials. Use environment variables or secret storage.102103### Pagination patterns104105| Pattern | Detection | Handling |106| --- | --- | --- |107| **Offset** | `?offset=0&limit=100` | Increment offset until empty page |108| **Cursor** | Response has `next_cursor` field | Pass cursor to next request |109| **Link header** | `Link: <url>; rel="next"` | Follow `rel="next"` until absent |110| **Page number** | `?page=1&per_page=50` | Increment page until empty |111112Set a maximum page limit (default: 100 pages) to prevent runaway loops.113114### Retry and timeout115116| Rule | Value |117| --- | --- |118| Timeout per request | 30 seconds |119| Retries on 429/5xx | 3 with exponential backoff (1s, 2s, 4s) |120| Retries on network error | 2 |121| Never retry | 400, 401, 403, 404 (client errors are not transient) |122123### Output124125A flat table from all pages combined. Report: total records, pages fetched,126any errors skipped.127128## SQL129130### What to ask1311321. What database engine? (PostgreSQL, SQL Server, MySQL, SQLite)1332. Connection string or host/port/database?1343. What table or query?135136### Security rules137138| Rule | Reason |139| --- | --- |140| **Always use parameterized queries** | Prevents SQL injection |141| **Never interpolate user input into SQL** | Even for table names; use allowlists |142| **Read-only connection** | The pipeline only reads; never write |143| **Credentials in env vars** | Never in code, never in logs |144145### Query patterns146147```sql148-- Simple table read149SELECT * FROM schema.table_name LIMIT 1000;150151-- Filtered read (parameterized)152SELECT * FROM sales WHERE region = @region AND date >= @start_date;153154-- Aggregated read (push aggregation to the database when possible)155SELECT region, month, SUM(revenue) AS revenue156FROM sales157GROUP BY region, month;158```159160Push aggregation and filtering to the database when possible. Pulling raw data161and aggregating in the LLM wastes tokens and is slower.162163### Output164165A table. Report: row count, column count, query execution time, database engine.166167## Excel168169### What to ask1701711. Which sheet? (default: first sheet)1722. Does the data start at A1 or is there a header region to skip?1733. Are there named ranges?174175### Quirks to handle176177| Problem | Detection | Fix |178| --- | --- | --- |179| Multiple sheets | Workbook has > 1 sheet | Ask which sheet; default to first |180| Header not in row 1 | First rows are title/metadata | Ask for header row number |181| Merged cells | Values span multiple rows/columns | Unmerge and fill down |182| Formulas | Cells contain formulas, not values | Read values, not formulas |183| Mixed types in column | Numbers and text in same column | Coerce to string; flag for data-preparation |184| Date serial numbers | Dates stored as integers (e.g., 45678) | Convert using Excel epoch (1899-12-30) |185186### Output187188A table from the specified sheet and range. Report: sheet name, row count,189column count, any merged cells detected.190191## Parquet / Arrow192193### What to ask194195- Path to the file or directory (partitioned datasets use directories)196197### Advantages198199Parquet is self-describing: schema, types, and encoding are embedded. No200delimiter guessing, no encoding issues, no header detection.201202### Quirks to handle203204| Problem | Detection | Fix |205| --- | --- | --- |206| Partitioned directory | Path is a directory with `part-*.parquet` files | Read all partitions |207| Nested columns (struct/list) | Schema shows complex types | Flatten or ask user which fields |208| Large file | > 1M rows | Sample or filter before loading all |209210### Output211212A typed table. Report: row count, column count, schema summary (types from213the Parquet metadata).214215## Error Handling (all connectors)216217| Situation | Action |218| --- | --- |219| File not found | Report the exact path tried. Ask user to verify. |220| Permission denied | Report the error. Do not retry. Ask user to fix permissions. |221| Empty dataset (0 rows) | Report it. Push back: "file exists but has no data rows." |222| Partial data (truncated) | Report row count. Ask if this is expected. |223| Unsupported format | State what was detected. Ask user for the correct format. |224225Never fail silently. Every error must produce a specific, actionable message.226227## Output Contract228229Pass to the next module (`data-preparation`):230231- The loaded dataset (or a reference to it)232- A one-line summary: format, row count, column count, source path233- Any warnings (encoding fallback, partial data, skipped errors)