Skip to content

executing sql queries on tabular data on client side using duckdb wasm - #1

Draft
jose-donato wants to merge 2 commits into
mainfrom
feat/sql_duckdb
Draft

executing sql queries on tabular data on client side using duckdb wasm#1
jose-donato wants to merge 2 commits into
mainfrom
feat/sql_duckdb

Conversation

@jose-donato

@jose-donato jose-donato commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Client SQL (browser DuckDB-WASM)

Widgets-as-tables: the workspace registers dashboard widget rows into a browser DuckDB-WASM instance. Agents with the client-sql feature write DuckDB SQL; the frontend executes locally and re-POSTs only result rows.

Activation

  1. Agent agents.json declares "features": { "client-sql": true }.
  2. Workspace echoes workspace_options["client-sql"] = true.
  3. For each tabular dashboard widget with loaded rows, workspace attaches metadata.data_table (dialect: "duckdb-wasm").
  4. Rita advertises ## Client-Queryable Widgets and registers the execute_client_sql tool when queryable widgets exist.
  5. First query lazy-loads wasm (~35MB, cached), registers tables, runs SQL.

Agents without the flag: zero protocol change.

Protocol

Function call execute_client_sql

{
  function: "execute_client_sql",
  input_arguments: {
    queries: Array<{
      sql: string;                 // SELECT/WITH only
      widget_uuids: string[];      // tables to ensure registered
      row_limit?: number;          // default 500, max 1000
    }>  // 1–5 queries per emission
  }
}

Results are order-correlated with queries. Success → convertToCopilotData({ rowData, rowCount }). Failure → { error_type, content } with verbatim DuckDB message.

Schema advertisement — metadata.data_table

{
  dialect: "duckdb-wasm",
  table_name: string,   // sanitize(name)_uuid.slice(0,8)
  description?: string,
  row_count?: number,
  columns: { name, type, label? }[]
}

Discriminator dialect avoids collision with Snowflake metadata.schema (rita duck-types that separately).

Safety

Browser engine after init:

  • SET enable_external_access=false
  • SET lock_configuration=true

SQL gate (SELECT/WITH only): deny ATTACH/DETACH/INSTALL/LOAD/COPY/PRAGMA/SET/CALL/multi-statement. Queries wrap with outer LIMIT.

Agent (rita) behaviour

  • Tool is a no-execute round-trip; harness emits one SSE batch (one-emission invariant).
  • On re-POST: rows land in pendingTables as client_sql_<djb2(sql)> so SQL family + execute_code keep working.
  • Prompt steers: prefer execute_client_sql over full get_widget_data for filter/aggregate/join on client-queryable widgets (prompt only — no content-based harness routing).

Limits

Limit Value
Rows per table 100k (register cap)
Result rows default 500 / max 1000
Concurrent registered tables 32 (LRU)
Query timeout 10s
Queries per emission 5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant