Changelog¶
All notable changes to doc-processing-std-tools are recorded here. Versions follow vMAJOR.MINOR.PATCH, equal to pyproject.toml's version, and every release is tagged.
Unreleased¶
Nothing yet.
0.6.1 — 2026-10-09¶
A security and documentation release: the desktop server's key input can no longer run
commands or slip past the confirmation gate, the private-address check covers every non-public address, and the docs site is
ready to be linked publicly. Upgrade by pinning @v0.6.1.
Migration notes¶
- The fetch tools and the browser refuse every address that is not public. Carrier-grade NAT addresses (
100.64.0.0/10, which Tailscale uses),0.0.0.0, the IETF protocol block192.0.0.0/24, the benchmarking, documentation and reserved ranges, multicast, and IPv4 addresses inside IPv6 forms were reachable before and are now refused. Iffetch_webpage,fetch_imageor the browser reach an internal host at such an address, add its hostname toDPTTOOLS_WEB_FETCH_ALLOW_HOSTSandDPTTOOLS_BROWSER_ALLOW_HOSTS. - The desktop server checks key names. Each key in
computer_key,computer_hold_keyand the click tools'modifiersmust be a single character or a key name (letters, digits and_, such asPage_DownorXF86AudioMute). A name that starts with a digit must be a hex keysym (0x1008ff13) or one of the3270_*names:xdotoolreads any other, such as119, as a raw key code. Anything else is refused with anError:naming it. Every real X key name still works; a client that sent other text as a key gets an error instead of a silent no-op. Upgrade: this closes a security issue (below). - The desktop confirmation gate covers more. With
DPTTOOLS_COMPUTER_CONFIRM=denyorelicit, a chord that contains a gated chord is gated too (ctrl+shift+w,alt+shift+F4,ctrl+Delete,Alt_L+F4,alt+0xffc1,ctrl+U0077), and so are the click tools'modifiers(modifiers="alt+F4"). A pipeline ondenythat pressed such a chord now gets anError:; withoff, the default, nothing changes. Separately, whatever the gate's setting,computer_typerefuses control characters other than tab, newline and carriage return; press keys such as Delete, Escape or BackSpace withcomputer_key. ocr_pdfoutput can differ. Pages are labelled in document order, and the note on a result cut on a page boundary names exactly the pages left out (Re-call ocr_pdf with pages='3,7' to read them.). Code that parses the labels or the note should be checked against the new form.- Install hints in errors changed wording. A missing optional library now gives "Install the
[docs]extra." rather than a pip command; code that matches the old text must match the new one.
Added¶
- The docs site's eight recipes are written: OCR a scanned PDF, Office files to page images, search then summarise, JavaScript-rendered pages, portal download to text, desktop actions with hooks, skills setup, and the launcher with other MCP clients. Each has its goal, steps, what to validate and the tests behind it, and each example was run against real services or software (LLMWhisperer, Tavily, LibreOffice, Chromium, a virtual desktop and a toolkit agent). The home page, the server pages and the README link them.
- The docs site has a link-preview card. Every page carries Open Graph and Twitter tags (title, description, the card image), from a theme override in
overrides/, so a shared link shows a preview. The site also publishes arobots.txtthat names the sitemap, and the Architecture page opens with a diagram of the launcher, the servers and the safety controls.
Changed¶
- The README links the documentation site and gains a Documentation section, as the toolkit's README has: how to serve the site locally, an index of its key pages, the API reference, and the
llms.txt/llms-full.txtfiles for coding agents. Its Overview now mentions the two optional servers. - Missing-dependency errors and tool descriptions name the extra to install ("Install the
[docs]extra.") instead of giving a pip command for the package. std-tools is not on PyPI, so that command could install someone else's package of the same name. 47 messages and docstrings change; code that matches the old error text must match the new wording. - The changelog and the module docstrings shown on the API pages no longer carry internal planning IDs.
- The security documentation matches the code.
browser_run_scriptis described as what it is: model-written Python running as the server's user, which can open connections that bypass the egress proxy and read the process environment, so enable it only whereexecute_commandwould be acceptable. Its loopback DevTools port, the egress proxy over the browser's own traffic and the fresh browser per session are described for the modes that have them: incdpmode the script attaches to the configured endpoint and no proxy applies. "Noeval/execof model input" now says "in the server process". The output-truncation row names what is not cut (directory listings, memory views and memory search). The browser page says downloads have no size or count limit of their own, so the container's disk quota is the control. The README's old "Security Model" section is replaced by a short summary that links the Security guide. The computer page says what the desktop confirmation gate does not know: an application's own shortcuts, keys such asXF86Close, typed text and clicks. - The Tool Reference page formats each description for reading (RST
``x``becomes code, the Args section a list), and keeps the exact text the model receives in a collapsed block under each tool. Code in table cells stays on one line, and wide tables scroll inside their box on a phone. The examples use one model ID,claude-sonnet-5, and the home page has a byline. - The home page and the quickstart say up front, in a "Source code" note, that the code is in a private repository, that the pages document every tool, setting and API, and how to ask to review the code. The footer of every page reads the same sentence.
- Browser tool counts read the same everywhere: 18
browser_*tools (core) or 27 (full), plusfetch_webpage_rendered. Thellms.txtintroduction names the browser and desktop servers.
Fixed¶
- Security:
computer_keycould run commands on the virtual desktop. Its text was split on spaces and every word went toxdotoolas a separate argument, andxdotoolreads a word that names one of its commands as the start of a chained command. Socomputer_key("a exec touch /tmp/x")rantouch, with the server's environment, API keys included: command execution for a deployment that exposes only the desktop tools, and a way past hooks that watchexecute_command. Clickmodifiersandcomputer_hold_keyalso passed model text to the same parser. Now every key is checked (a single character or a key name, never anxdotoolcommand word), each chord goes to its ownxdotoolcall after--, andkeydown/keyupget--too. Host mode (pynput) was not affected. Reproduced in the Linux test image before the fix, and refused after it, with real keys still pressed. - Desktop key names other than the built-in ones reach
xdotoolas written. Every name the server did not know (it knowsctrl,Return,Tab,F1–F12and a few more) was lowercased, and X key names are case-sensitive:XF86AudioMute,ISO_Left_Tab,U20ACorF13were silently ignored while the tool reported them pressed, and3270_Enterpressed a different key. The descriptions ofcomputer_key,computer_hold_keyand the click tools'modifiersnow state which keys are accepted. - Security: the desktop confirmation gate could be bypassed. The click tools never showed their
modifiersto the gate, and the modifiers are pressed before the click, socomputer_left_click(x, y, modifiers="alt+F4")closed the focused window underDPTTOOLS_COMPUTER_CONFIRM=deny. The gate also matched chords exactly, so an extra key (alt+shift+F4,ctrl+shift+w,ctrl+Delete) or, on the virtual desktop, a side-specific X name (Alt_L+F4,Control_L+w,KP_Delete) got past it. Numeric spellings got past it too: a hex keysym (0xffffis Delete,alt+0xffc1is alt+F4), a Unicode form (ctrl+U0077is ctrl+w), or a raw key code, whichxdotoolreads from any token that starts with a digit and is not a key name (119is Delete,64+70alt+F4, on a standard keymap); each was checked live withxev. Now the click tools check their modifiers before anything else and show them to the gate as one chord; a chord is gated when it contains a gated chord, with side-specific names and hex and Unicode spellings read as the key they name; and a digit-led token that is not a hex keysym or a3270_*name is refused. A third route went throughcomputer_type:xdotooltypes a character with the key that produces it, and the Delete key produces U+007F, so on the virtual desktopcomputer_type("\x7f")pressed Delete.computer_typenow refuses control characters other than tab, newline and carriage return (host mode on Windows sends U+007F as a character, not the Delete key). Present since 0.6.0; only deployments that setDPTTOOLS_COMPUTER_CONFIRMrelied on the gate. - The desktop's plus key.
+separates the keys of a chord, so the plus key itself could not be pressed:computer_key("+")was refused and"ctrl++"pressedctrlalone. A+where a key is expected is now the plus key ("+","ctrl++"), and a chord with a dangling or doubled separator ("ctrl+","ctrl++a") is refused instead of being read as a shorter chord. - The private-address check missed ranges. It refused seven networks (
127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,::1,fc00::/7), so0.0.0.0(which reaches localhost on Linux),::ffff:127.0.0.1, IPv6 link-local, carrier-grade NAT, NAT64 and 6to4 forms of private addresses got through, contrary to the documented policy. It now refuses every block the IANA special-purpose address registries list as not globally reachable, multicast, reserved addresses and any IPv6 address outside2000::/3, and judges an IPv6 address that carries an IPv4 one (IPv4-mapped, 6to4, Teredo, NAT64) by that IPv4 address. The blocks are written out in the code rather than read fromipaddress.is_global, whose tables depend on the Python release (on 3.10.11 they call192.0.0.8and3fff::1global), so the result is the same on every supported Python.fetch_webpage,fetch_image, the browser's egress proxy and itscdp-mode checks all use it. ocr_pdfpage labels. OCR returns the requested pages in document order, and the--- Page N ---labels now follow it. An open-ended range (pages="21-") was numbered from 1 instead of from its start, and a list out of order ("3,1") was labelled in the order given, so page 1's text came back as--- Page 3 ---.ocr_pdf's note on a result cut on a page boundary now names exactly the pages left out (Re-call ocr_pdf with pages='3,7'). It gave one range from the first page left out to the last, which could take in pages never requested ('2-7'forpages="1-3,7", so following it paid for pages 4 to 6) or be invalid ('5-2').
0.6.0 — 2026-10-03¶
Migration notes¶
fetch_webpageno longer usesDPTTOOLS_SANDBOX_TIMEOUT. Its timeout is nowDPTTOOLS_WEB_FETCH_TIMEOUT, default 30 s. If you raised the sandbox timeout to allow slow pages, set the new variable when you upgrade.web_searchoutput has a newusagekey. Strict-schema parsers must allow it.search_type="news"no longer forces Tavily's 2-creditadvanceddepth; passsearch_depth="advanced"to keep it.DPTTOOLS_OCR_TIMEOUTis validated at start-up. A non-integer or non-positive value now raises aConfigErrornaming the variable, instead of silently falling back to 180 s. The value is read once per process, so restart after changing it. Values outside 30–600 are still clamped.fetch_webpagereturns a JSON object by default:url,final_url,status,content_type,title,text,truncated,total_chars,offset,next_offset,has_more,byte_cap_reached,likely_js_rendered. Code that used the return value as page text should readtext, or passstructured=Falsefor the old plain string. Non-text responses are now refused, and plain text and JSON are no longer run through the HTML-to-text step.
Added¶
DPTTOOLS_WEB_FETCH_TIMEOUT(default 30 s) forfetch_webpage, with connects capped at 10 s. A slow or hostile URL can no longer hold a fetch for the code-execution budget (often several minutes).web_searchreports per-callusage, and takes an optionalsearch_depthparameter (basic|advanced|fast|ultra-fast, Tavily only). Tavily's own usage is passed through (include_usage), with a fallback estimate clearly markedestimated; Serper and Brave reportprovider_reported: falserather than an invented cost.- Images are scaled to model-safe limits.
read_image,render_document_page,render_document_thumbnail,read_document_pages_as_imagesandtake_screenshotscale any image aboveDPTTOOLS_IMAGE_MAX_EDGE_PX(default 1568 px long edge) orDPTTOOLS_IMAGE_MAX_MB(default 3 MB). Images within the limits are returned byte-identical. The shared helper,_images.fit_image, also reports the scale it applied. tests/integration/test_toolkit_compat.pychecks std-tools against an installeddoc-processing-toolkitwithout a model call: the skills catalog reaches the system prompt, and an in-processread_imagereaches the toolkit as an image. It is skipped when the toolkit is not installed.- README section "Compatibility with doc-processing-toolkit": tested versions, the in-process image requirement (toolkit 0.5.1+), the skills naming rule, passing
envto stdio servers, and a working pre-built-session example for a toolkit issue (0.5.2 and earlier) that leaves the skills catalog empty in-process and withmcp_commandconfigs. .env.examplelisting every environment variable with its default, and a Configuration section rebuilt as one table per area (default, accepted values, when it is read), plus how configuration is loaded. Both are generated from one table in_config.pybyscripts/gen_reference.py; unit tests fail if a variable or a tool goes undocumented.doc_processing_std_tools.__version__, read from the installed package metadata, so a running deployment can report its version.convert_document(path, to, outdir=None, page="all", overwrite=False): converts Office and OpenDocument files with LibreOffice to pdf, docx, xlsx, pptx, odt, ods, odp, csv, html, txt, or png/jpg page images (through PDF and pymupdf), writes next to the source or into an existingoutdir, never replaces a file unlessoverwrite=True, and returns the output paths as JSON. New settingsDPTTOOLS_SOFFICE_BINandDPTTOOLS_CONVERT_TIMEOUT_S(default 120, the previous fixed value). The composed server now has 55 tools.fetch_webpagepaging (offset,next_offset,has_more), alikely_js_renderedhint, and the settingsDPTTOOLS_WEB_FETCH_MAX_BYTES,DPTTOOLS_WEB_FETCH_MAX_REDIRECTSandDPTTOOLS_WEB_FETCH_ALLOW_HOSTS(an operator allow-list of internal hostnames, still resolved once and pinned).fetch_webpage(format="text" | "markdown" | "html")and the optional[extract]extra (trafilatura): with it, text and Markdown hold the page's main content without navigation and footers; without it, a built-in extractor (now also producing Markdown) is used. The result reportsformatandextractor.[all]includes[extract].fetch_image(url): downloads a PNG, JPEG, GIF or WebP image underfetch_webpage's SSRF policy, refuses images overDPTTOOLS_FETCH_IMAGE_MAX_BYTES(default 10,000,000) before downloading, checks the real format and pixel count, and returns a caption plus the image scaled to the model limits.fetch_webpage(include_assets=True)adds boundedimages(30) andlinks(100) reference lists. The[web]extra now includes Pillow. The composed server now has 56 tools.docker/integration.Dockerfileandtests/integration/run_in_docker.py: a Linux test image (Python 3.12, LibreOffice, Xvfb, xdotool, CJK fonts) that runs the integration suite, so LibreOffice and virtual-display tests run on any machine with Docker. A.dockerignorekeeps.envand local environments out of images.- Optional browser server (
browser_server,[browser]extra): drives Chromium through element refs, modelled on Anthropic's browser use toolset, withbrowser_<member>tools (coreprofile: 18,full: 27). It has three modes (launch,persistent,cdp), one browser context per MCP session, an idle reaper, and a Tab Context footer in every result. Playwright runs on its own thread, so the browser survives callers that create a new event loop per call. It is off by default: the launcher composes it only withDPTTOOLS_ENABLE_BROWSER=true. NewDPTTOOLS_BROWSER_*settings are validated only when it is enabled. - Browser network policy and confirmation gate. Every connection a launched Chromium makes goes through an egress proxy inside std-tools that applies the domain lists, refuses private and reserved addresses, and connects to the address it validated, closing DNS rebinding. That covers sub-resources, fetch and WebSockets. Navigation refuses non-web schemes and re-checks redirects, and service workers are blocked.
DPTTOOLS_BROWSER_CONFIRM=off(default) |deny|elicitgates consequential clicks, password entry, uploads and scripts. Withoff, approval belongs to the client app. Includes theBROWSER_SAFETY_PROMPTtemplate. - Browser downloads are saved per session and reported once, with a path the document tools open. Opt-in tools (
DPTTOOLS_BROWSER_ENABLE):browser_javascript_exec,browser_read_console,browser_read_network(both drained per read, per tab) andbrowser_file_upload(only files insideDPTTOOLS_BROWSER_UPLOAD_DIR). browser_run_script(opt-in): runs model-written Python with Playwright against the session's tab. It runs in a per-session child process, started without the environment variables whose names look like secrets, attached over a loopback DevTools port that is opened only while the tool is enabled (incdpmode, to the configured endpoint). Variables persist between calls; inlaunchandpersistentmodes the browser's own traffic still goes through the egress proxy; a timeout (DPTTOOLS_BROWSER_SCRIPT_TIMEOUT_S, 60) kills the process tree and resets the namespace. The script itself is not sandboxed: it can open its own connections, bypassing the proxy, and read the server's environment (stated in the docs from 0.6.1).fetch_webpage_rendered(browser server):fetch_webpage's JSON envelope (plus"rendered": true) from a page rendered by Chromium, for single-page apps and other pagesfetch_webpagesees as an empty shell. Each call uses a fresh, credential-free context behind the egress proxy, closed afterwards; it exists only where the browser server is enabled.- Optional computer (desktop) server (
computer_server,[computer]extra): 17computer_<member>tools modelled on Anthropic's computer use toolset.virtualbackend (default): an Xvfb display per MCP session driven throughxdotool, with an optional VNC view; Linux containers only.hostbackend: the real screen throughpynputandmss, one session at a time, on a chosen monitor, with per-monitor DPI awareness on Windows, a kill switch (top-left corner orDPTTOOLS_COMPUTER_KILL_HOTKEY) and a pause on human activity. Large screens are scaled for the model and coordinates mapped back.DPTTOOLS_COMPUTER_CONFIRM=off(default) |deny|elicitgates host sessions and key chords that close, quit or delete. Off by default: the launcher composes it only withDPTTOOLS_ENABLE_COMPUTER=true. On Linux the extra leaves outpynput, whoseevdevdependency compiles from source.
Changed¶
DPTTOOLS_OCR_TIMEOUTis read through the sharedToolsConfig, like every other variable. It andLLMWHISPERER_API_KEYare now documented in the README.- The
mcpfloor is now>=1.25, the range the toolkit already requires and the one std-tools is tested on. - Contributor guides for coding agents (
CLAUDE.md,AGENTS.md). take_screenshotand the computer server's host backend share their capture code (_display.py); the browser and computer servers share their MCP-session keys (_sessions.py). The Screenshot Server README entry now says plainly that it captures the real screen of the machine the server runs on.- The README installs from the repository at the release tag (
pip install "doc-processing-std-tools[...] @ git+https://github.com/rzoeb/doc-processing-std-tools.git@v0.6.0"), as the docs site does: std-tools is not on PyPI, and a barepip install doc-processing-std-toolswould fetch whatever package holds that name there. Unit tests now also check the docs site: its generated tool reference and llms files are current, its configuration page lists every variable, no page names an unknown variable, and no page carries an email address, a link to the repository or a Vercel preview URL.
Fixed¶
apply_patchholds the read-modify-write lock likeedit_file. In the composed server two overlapping patches, or a patch and anedit_filecall, could both report success while the last write silently discarded the other change.- Images are turned upright before they are resized. A phone photo stored sideways with an EXIF orientation tag came back sideways once
fit_imagehad to shrink it, because re-encoding dropped the tag. Images that need no resizing are still returned byte-identical. - Colour-key transparency survives resizing. An RGB or greyscale PNG made transparent with a
tRNSchunk (no alpha channel) was treated as opaque and could be re-encoded as JPEG. browser_run_scriptresponses are bounded in the child process. Output is cut to the browser's 50,000-character limit, a call returns at most five screenshots, each fitted to the image limits within an overall budget, so a response can no longer exceed the 64 MiB pipe limit; if a response is still too large or unreadable, the worker is stopped and the namespace reset. The child keeps the protocol on private file descriptors, so a script that writes to the real stdout, reads input or starts a subprocess cannot corrupt it. Browser truncation notices no longer end with a stray number (the limit was passed as the notice's hint).browser_run_scriptno longer lets one client's script reach another client's pages. A script attaches to the whole browser, so whilerun_scriptis enabled only one browser session is open at a time (a second client gets an error until the first is idle), inlaunchmode each session starts with a fresh browser, andcdpmode requiresDPTTOOLS_BROWSER_CDP_SHARE_TABS=true(aConfigErrorotherwise). To serve several clients with scripts enabled, run one server per client.- Exclusive creates under concurrency.
create_fileandmemory_createcreate the file exclusively, andmemory_createandmemory_renamehold the memory lock, so overlapping calls for the same path can no longer both succeed with one silently overwriting the other. - Every file change in the File System and Memory servers holds the lock, not only read-modify-write edits.
write_file,create_file,delete_file,move_file,copy_file,write_memory,delete_memoryandmemory_deletenow take it too. Before, two overlapping overwrites could interleave (the shorter text followed by the longer one's tail, invalid JSON for a memory entry), and an edit overlapping a delete or move wrote the old file back. A unit test fails if a tool changes a file outside the lock. - A
browser_run_scriptscreenshot sets the click scaling. Coordinates are mapped back through the scale of the latest screenshot, but a script'sawait screenshot()did not update it, so with a viewport larger thanDPTTOOLS_IMAGE_MAX_EDGE_PXa click read off a script's screenshot missed (by about 20% at 1920x1080). The worker now reports each screenshot's scale; a viewport screenshot updates the mapping, a full-page one does not. tests/integration/run_in_docker.pymakes the integration folder pytest's default (testpaths) instead of a fixed argument, so-- tests/integration/<file>.pyruns that file only.- Host mode picks the real primary monitor on Linux. With
DPTTOOLS_COMPUTER_MONITOR=primary(the default) the computer server used the monitor at the desktop's origin, which on X11 need not be the primary output. It now uses the monitor mss marks primary (the XRandR primary output on X11, the primary display on Windows) and falls back to the origin rule. The[computer]extra now requiresmss>=10.2, the first release that reports it. - The Dockerfile examples install
git(absent frompython:3.12-slim, so thegit+httpsinstall failed) and show how to pass a GitHub token as a BuildKit build secret without storing it in the image. - The browser integration tests restore the environment when Chromium cannot start. Before, a skip during start-up left loopback allow-lists set for every later test.
- Child processes no longer inherit the server's stdin.
execute_command,execute_skill_script, the LibreOffice conversions and the computer server's helpers start their children with stdin closed. Under the stdio launcher the server's stdin is the MCP message stream, so a command that read input could consume protocol messages or hang the session. - Tool descriptions the model reads:
read_excelsays it returns saved cell values (not formulas) from the sheet active when the file was saved;load_skillstates its listing limits instead of a private constant name;take_window_screenshotno longer cites a version number. TheDPTTOOLS_COMPUTER_CONFIRMdescription lists all seven chords the gate checks, and the README explains how to reach the VNC view safely. - Tavily search authenticates with a Bearer header. The key used to travel in the JSON body, which Tavily no longer documents and which development-tier keys reject with a 401. Errors returned by
web_searchno longer include request URLs or the API key. format_search_resultsacceptsweb_search's output unchanged. It used to accept only a bare JSON array, so the two tools could not be chained. Plain arrays still work as before.- The live OCR integration tests skip when the
[ocr]extra is missing. Before, a key in.envwithout the client installed made them fail instead of skip. - The composed server no longer freezes on a slow tool. FastMCP calls synchronous tools on its event loop, so one OCR job, LibreOffice conversion or long command stalled every other request and the transport. The launcher now registers every synchronous tool as an async wrapper that runs it on a worker thread. Names, descriptions and schemas are unchanged, and a test checks this.
edit_file,memory_str_replaceandmemory_insertlock their read-modify-write, so overlapping calls cannot lose updates. - Concurrent LibreOffice conversions in
render_document_page,render_document_thumbnailandread_document_pages_as_imagesno longer collide: each run gets its own profile (-env:UserInstallation), so a second conversion no longer exits without output. Failed conversions no longer leave temporary directories behind. fetch_webpageno longer decodes images, PDFs or other binary responses into garbage: they are refused, with their size, before the body is downloaded. The page charset now comes from a byte-order mark, the header or<meta charset>, so pages that declare their encoding only in HTML decode correctly.take_screenshoton Linux with mss 10.2: captures now usemss.MSSwith thexgetimagebackend. mss'sdefaultbackend, called from a worker thread (where the composed server runs every capture), left the X server unable to map new windows.- The browser and computer servers tolerate the placeholders that strict function calling (OpenAI) sends for unused optional arguments:
tab_id0 means the active tab andbrowser_navigateopens a tab when none is open whatevertab_idsays;ref=""means no ref;x=0, y=0next to a ref is ignored;browser_scrollandcomputer_scrollat (0, 0) scroll at the centre. Found in end-to-end tests with a model that uses strict function calling.
0.5.0 — baseline (tag v0.5.0, commit 565c3e4)¶
The first tagged release. It contains 8 FastMCP tool servers with 54 tools: file system, web search, memory, document processing, code execution, screenshot, image tools and skills, plus the composed launcher python -m doc_processing_std_tools. Changes before this release are recorded in the git history only.
Before the first tag¶
The 0.5.0 baseline above is the first tagged release; until then, changes were recorded in the git history only. In summary:
0.5.0 — 2026-06-09¶
- New
read_document_pages_as_images: renders several PDF or Office pages as images, the vision fallback for scanned and visual documents. - Richer Office extraction, all additive:
read_wordreads headers, footers and text boxes, and reports embedded images.read_excelreports merged ranges and whether the sheet has images or charts.read_powerpointreads tables and grouped shapes, and counts images and charts per slide.
0.4.0 — 2026-05-18¶
- Breaking:
extract_pdf_via_ocris replaced byocr_pdf(path, pages)andocr_image(path), which call LLMWhisperer directly. OCR gains a deadline (DPTTOOLS_OCR_TIMEOUT), page-aware truncation and sanitised errors. sanitize_pathno longer claims to contain paths: it rejects only NUL bytes, and the container is the boundary.take_screenshotno longer creates folders.- Image tools keep orientation, colour profiles and quality, add a
frameparameter for multi-frame images, and refuse decompression bombs.
0.3.1 — 2026-05-09¶
read_imagereports the image format detected from the file's bytes, not its extension.
0.3.0 — 2026-05-07¶
read_image, the page renderers andtake_screenshotreturn images the model can see, instead of base64 text.- New
get_image_metadata.
0.2.2 — 2026-05-06¶
- Tool descriptions rewritten so each states its accepted formats and points to the right alternative.
0.2.1 — 2026-05-01¶
fetch_webpagere-validates every redirect against the SSRF policy.apply_patchrefuses a patch whose context no longer matches the file.search_in_filesskips files over the size limit.
0.2.0 — 2026-05-01¶
- Skills server rebuilt: PyYAML frontmatter parsing,
pathanddiagnosticsinlist_skills, the<skill_content>wrapper inload_skill, andmake_skills_server(). - New composed launcher,
python -m doc_processing_std_tools.
0.1.0¶
- First version: the file system, web search, memory, document processing, code execution, screenshot, image tools and skills servers.