Surfaced while comparing kbagent's KeboolaClient against the official sapi-python-client (kbcstorage) during the in-process library facade work (#416 / #415).
Headline: kbagent is already at parity or ahead of the official client on almost every axis — timeouts (kbcstorage has none), 429 + Retry-After handling, connect/read-timeout retries, connection pooling, bucket sharing/linking (kbcstorage raise NotImplementedError), typed-table creation, multi-cloud upload/download with no boto3/azure/gcs dependency, and the Query Service (kbcstorage has none). The items below are the genuine gaps worth triaging — none block the facade.
File refs are against src/keboola_agent_cli/.
Storage export / import (highest value)
Robustness
Library facade (lib.py) enhancements
Lower priority / validate demand first
Each box is independently shippable. Suggest cherry-picking the high export/import items + the two med robustness items first; the facade enhancements can follow as the in-process library use case (jasnost) matures.
Surfaced while comparing kbagent's
KeboolaClientagainst the officialsapi-python-client(kbcstorage) during the in-process library facade work (#416 / #415).Headline: kbagent is already at parity or ahead of the official client on almost every axis — timeouts (kbcstorage has none), 429 +
Retry-Afterhandling, connect/read-timeout retries, connection pooling, bucket sharing/linking (kbcstorageraise NotImplementedError), typed-table creation, multi-cloud upload/download with no boto3/azure/gcs dependency, and the Query Service (kbcstorage has none). The items below are the genuine gaps worth triaging — none block the facade.File refs are against
src/keboola_agent_cli/.Storage export / import (highest value)
where-column filter on export / preview / download. kbcstorage exposeswhere_column+where_operator(eq/neq) +where_valuesonpreview/export/export_raw(tables.py). kbagent'sget_table_data_preview/export_table_asyncsupport onlycolumns+limit— no way to export "rows where status = active" via the credential-only Storage path (the Query Service path needs a workspace). Scope: medium (client + service +download-table --where-*flags).changed_since/changed_untilincremental export. kbcstorage threads these through every export path; kbagent has no equivalent (grep returns zero Storage hits). Blocks "pull only rows changed since my last sync" without a full table download. Scope: small-medium.add-column(typed) to match the existingdelete-column. kbagent can create a fully-typed table and drop columns, but cannot add a typed column to an existing table (Storage APIPOST /tables/{id}/columnssupports it). Internal asymmetry, not a kbcstorage gap. Scope: small-medium (reuse_parse_column_spec).escaped_by/without_headers/columnson import.import_table_async/upload_tablehard-code onlydelimiter+enclosure; headerless or backslash-escaped CSVs can't be loaded. Scope: small.file_formatrfc / escaped / raw.export_table_asynconly switches csv vs parquet; always RFC CSV. Scope: small.Robustness
http_base.pyis bareBACKOFF_BASE * 2**attemptwith no jitter; kbagent's headline parallel multi-project fan-out (MCP read tools,org_service,lineage_service) makes a stack-wide 5xx retry in lock-step. Add equal/full jitter + aRETRY_JITTERconstant. Scope: one-liner.download_sliced_file/_CloudDownloader.stream_to_fileand the manifest fetch are one-shothttpxstreams with no retry — one flaky slice aborts a multi-GB export. Wrap in a bounded retry on 429/5xx/TransportError reusing the existing retry constants. Scope: ~25 lines.httpx.Client._headersprivate API (client.pyseeds queue/query/encrypt sub-clients viaself._client._headers.copy()). Store the composed headers on the instance inBaseHttpClient.__init__and copy that. Scope: one-liner.Library facade (
lib.py) enhancementsKeboolaClient.lib.Files.upload(bytes)/read_bytescurrently stage through a temp dir (works, hardened in feat(lib): importable in-process library facade (Client/Files) (0.61.0) #416). A_upload_to_cloud(source: BinaryIO | bytes)+ adownload_to_bytesio(url)would let the facade skip temp files entirely. The AWS branch already materializes bytes for SigV4 hashing, so the lift is small. Scope: ~70 lines.Client.tables/Client.buckets/Client.jobsnamespaces mirroringClient.files, matching thekbcstorageidiom Keboola users know. Thin wrappers over existingKeboolaClientmethods. Scope: small-medium.upload_filereturn shape is stale. It echoes the prepare response, soFileEntry.createdafter an upload can beNoneandtagsis what you asked for, not server-canonical. Either re-fetchget_file_info(id)after upload or document the contract. Scope: ~5 lines.Lower priority / validate demand first
workspace loadCLI drops per-table load options (columns / where / datatypes /load-clone). The clientload_workspace_tablesalready posts the rawinputarray, so the payload flows through — it's CLI/service plumbing that narrows it. Scope: small-medium.flow schedule/scheduleand agent-task triggers but no data-event trigger. Decide whether this is intentionally out of scope vs flows before building. Scope: medium.create_raw(snapshot_id=...); kbagent hasclone-table/pull-table(branch materialization) but no named snapshot/restore. Validate demand. Scope: medium-large.create_configlacksstate/is_disabled/configurationIdkwargs (useful for idempotent provisioning with deterministic IDs). Scope: XS.list_fileslacksmax_id/run_idfilters (max_idenables descending-window pagination;run_idfinds files from a specific job run). Scope: ~6 lines.Each box is independently shippable. Suggest cherry-picking the high export/import items + the two med robustness items first; the facade enhancements can follow as the in-process library use case (jasnost) matures.