Knowledge base documents: one-shot PDF upload and metadata CRUD#428
Conversation
Add create/get/update/delete_ai_knowledge_base_document with full SDK + MCP + CLI parity. Create is one-shot from a local file path: presigned URL → S3 PUT → createAiKnowledgeBaseDocument, with step-tagged errors (file_read | presigned_url | s3_upload | kb_create) and no standalone presign tool. The .pdf extension (case-insensitive), the 20 MiB cap, and the description requirement (1-900 chars) are enforced client-side because the backend skips file validation when the document arrives as a URL — this path's only guardrail. documentUrl carries the persistent download URL from createPresignedUrl, not the single-use upload URL. Update is metadata-only (name/description); no file replacement in v1. The create tool reads local files, so it stays excluded from the remote profile. Deletes require confirm=True; CLI writes gate on the access probe. Indexing is asynchronous — documents may not be searchable by agents immediately. Closes #413
f75253c to
e971e1c
Compare
adriannoes
left a comment
There was a problem hiding this comment.
Summary
Solid fourth-phase KB documents surface: one-shot PDF create with client-side .pdf/20 MiB/description guards, download URL (not PUT URL) as documentUrl, metadata-only update, delete confirmation, CLI probe gate, and create kept off the remote profile. Local checkout ran ruff and unit tests on an earlier tip; this review is against e971e1cb after rebase onto the #427 tip. Soft write unwrap is fixed here (_unwrap_document fails closed; create tags it as kb_create). One CLI/MCP parity gap remains before merge.
What worked well
- Wire path and tests lock
documentUrlto the persistent download URL and tag HTTP S3 failures withstep=s3_uploadplusbody_snippet. - Full SDK + MCP + CLI parity, registry, parity matrix, docs, and skills, including async-indexing callouts.
- Tip amend fail-closes null nested write payloads for documents (and brings the plain-text empty-get fix from the #427 tip).
Required before merge
- CLI
kb document getmust treat SDK{}as not-found (success: false, exit 1), mirroring MCP and the plain-text get pattern already on this tip, with a regression test.
Also noted
- Absolute "every pipeline failure carries
step" overstates the shared S3 uploader contract. HTTP status failures fromputare tagged; allowlistValueErrorand transport errors still bubble bare, same asAttachmentService. Optional follow-up: wrap both call sites, or narrow the docs wording to the HTTP-scoped tag.
Review path
- Worktree review against tip
e971e1cb(recheck after amend fromf75253c0); earlier local ruff + sdk/mcp/cli unit suite was green on the prior tip. - Adversarial passes + refutation kept CLI document empty-get; soft unwrap was open on the first tip and is fixed on this amend; put-exception step tagging stayed a shared-attachment summary note.
- Base is now
98c3a8d6(#427 tip), so stack alignment is in good shape aside from mirroring empty-get onto document get.
…3 PUT CLI `kb document get` now mirrors the MCP tool and the plain-text get: an empty SDK result returns success=false and exits 1 instead of reporting success on a document that does not exist. The S3 PUT call is wrapped so transport errors and the uploader's host-allowlist rejection raise KnowledgeBaseDocumentUploadError tagged step=s3_upload, making the documented step contract hold for every upload-stage failure instead of only HTTP >=400 results.
Plain-text and document get built the same success=false envelope and discovery hint inline; the data lookups phase would have added a third copy. One helper keeps the message and hint identical for every pipe-scoped knowledge base kind.
|
@adriannoes Thanks for the review — both findings verified and addressed, tip is now 7f997f6. Required (CLI document get empty-result): fixed in 94d87b7, details on the inline thread. Also noted (step-tag contract vs raising PUT): you're right on both halves — the docs claimed the absolute while transport errors and the allowlist The Validation on the tip: full suite 3618 passed / 39 skipped, ruff check + format, lint-imports, CLI help golden regenerated (exits-1 help text), parity/remote-profile drift guards green. |
There was a problem hiding this comment.
Rechecked tip 7f997f62 after your follow-ups. The CLI document empty-get path now mirrors MCP and plain-text get (_kb_not_found, exit 1, regression test), soft write unwrap stays fail-closed, and S3 PUT exceptions are tagged step=s3_upload as well. Local KB CLI/SDK unit tests and CI are green on tip. Approving.
Thanks for turning around the review notes so cleanly, @mocha06. The shared not-found helper and the stronger S3 wrap were especially welcome.
What worked well
- Empty-get parity with a regression test that locks the contract.
- Wrapping raising S3 PUT failures so the documented step taxonomy holds beyond HTTP status errors.
- Extracting
_kb_not_foundbefore a third KB kind would have duplicated the envelope.
Motivation
Fourth phase of the knowledge-base milestone (#413, depends on #412). Pipes can hold PDF documents as agent knowledge, but the API contract is a three-step dance (presign → S3 PUT → create) with no validation on the URL path — the backend's PDF/size checks only run for raw uploads, which this flow never uses. Agents and CLI users need a single safe call that does the whole pipeline and fails fast with a clear step tag instead of a late 422 or a silently unindexable document.
What ships
create_ai_knowledge_base_document(MCP) /pipefy kb document create --file …(CLI): one-shot create from a local PDF path — resolves the pipe's organization, mints a presigned URL, PUTs the bytes, then runscreateAiKnowledgeBaseDocumentwith the persistent download URL. Every failure carriesstep:file_read|presigned_url|s3_upload|kb_create. No standalone presign tool.get_ai_knowledge_base_document/pipefy kb document get: fetch by ID;contentis the stored document URL, not extracted text.update_ai_knowledge_base_document/pipefy kb document update: metadata-only (name/description) in v1; no file replacement.delete_ai_knowledge_base_document/pipefy kb document delete: preview-then-confirm (MCPconfirm=True, CLI--yes/prompt).KnowledgeBaseServicedocument methods reusing the attachment pipeline's presign mutation and S3 uploader (same host allowlist, no auth header leakage to S3, body snippet capped on errors).Proven contract (traced to the owning layer, not the schema)
documentUrlmust be the persistent download URL fromcreatePresignedUrl, not the single-use upload URL: the backend stores it and the async indexer fetches the PDF from it later. A pre-signed-PUT URL there would 403 at indexing time.application/pdfcontent-type and 20 MiB checks are conditional on a raw upload and are skipped when the document arrives as a URL. The toolkit enforces.pdf(case-insensitive), 20 MiB, anddescriptionrequired 1–900 chars before any network call.descriptionis required end-to-end even though the GraphQL schema marks it optional — same shared rule proven for plain texts in the previous phase. (The issue's "description ≤ 900" understated this; confirmed against the backing model and enforced as required.)manage_ai_agentson the pipe; the read probe (validate_knowledge_base_access) proves read access only, and its note says so.Behavior boundaries
confirm=Trueto execute).Docs & skills
docs/mcp/tools/knowledge-bases.md: document tool reference, upload pipeline, step-tag table, async-indexing note.docs/parity.md: +4 rows, tool count 168 → 172 (drift-guard line updated).README.md: counts and KB area row (6 → 10 tools).skills/ai-agents/pipefy-ai-agents/SKILL.md: document workflow guidance.Testing
Live verification against a test pipe through the reloaded MCP tools:
validate_knowledge_base_accesson pipeok:true, knowledge_base_count:3, read-only notecreate_ai_knowledge_base_documentwith a local PDFcontent=persistent download URLget_ai_knowledge_base_documentby idget_ai_knowledge_baseslists the doctype: knowledge_base_documentsupdate_ai_knowledge_base_documentname+descriptionupdatedAtbumped, content unchangedstep: file_read, nothing uploadedFile must be a .pdf: …,step:file_readdescription must be a non-empty stringrequires_confirmation:truepreviewdeleted_idreturned; follow-upget→ 404 (classifiednot_found)Size-cap and per-step failure paths are proven in-process (SDK/MCP/CLI unit tests) rather than by forcing pathological inputs through the live API. Full suite: 3612 passed / 39 skipped; ruff check + format, lint-imports, version verify, skill linters, and the parity/remote-profile drift guards all green.