Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
binutils \
&& rm -rf /var/lib/apt/lists/*

# ============================================
# Document processing: LibreOffice, qpdf, fonts
# ============================================
RUN apt-get update && apt-get install -y --no-install-recommends \
libreoffice-writer libreoffice-calc libreoffice-core libreoffice-common \
fonts-liberation fonts-dejavu-core fonts-noto-core \
qpdf \
&& rm -rf /var/lib/apt/lists/*

# ============================================
# Sandbox directory structure
# ============================================
Expand Down Expand Up @@ -288,6 +297,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \

COPY src/ /app/src/
COPY dashboard/ /app/dashboard/
COPY skills/ /opt/skills/

RUN find / -path /proc -prune -o -path /sys -prune -o \
\( -perm -4000 -o -perm -2000 \) -type f -exec chmod u-s,g-s {} + 2>/dev/null || true
Expand Down
35 changes: 35 additions & 0 deletions docker/nsjail-base.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,41 @@ mount {
mandatory: false
}

# Agent skills (DOCX, XLSX, etc.)
mount {
src: "/opt/skills"
dst: "/opt/skills"
is_bind: true
rw: false
mandatory: false
}

# LibreOffice shared resources
mount {
src: "/etc/libreoffice"
dst: "/etc/libreoffice"
is_bind: true
rw: false
mandatory: false
}

# Font configuration
mount {
src: "/etc/fonts"
dst: "/etc/fonts"
is_bind: true
rw: false
mandatory: false
}

mount {
src: "/usr/share/fonts"
dst: "/usr/share/fonts"
is_bind: true
rw: false
mandatory: false
}

# Writable tmpfs for temporary files
mount {
dst: "/tmp"
Expand Down
2 changes: 2 additions & 0 deletions docker/requirements/nodejs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ zod
handlebars
cheerio
marked
docx
pptxgenjs
6 changes: 4 additions & 2 deletions docker/requirements/python-documents.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

# PDF
PyPDF2>=3.0
pdfminer.six>=20221105
pdfminer>=20191125
pypdf>=4.0
pdfplumber>=0.10
pdfminer.six>=20231228
pdf2image>=1.16
reportlab>=4.0

# Office documents
python-docx>=1.1
python-pptx>=0.6
markitdown[pptx]>=0.1
mammoth>=1.6
docx2txt>=0.8
docx2python>=2.0
Expand Down
136 changes: 136 additions & 0 deletions docs/AGENT_SKILLS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Agent Skills Runtime

This document describes the agent skill dependencies embedded in the LibreCodeInterpreter Docker image to support specialized LibreChat agents.

## Overview

The image includes pre-installed skills, system binaries, and Python/Node packages required by the following LibreChat agents:

| Agent | Key Dependencies | Skills Directory |
|-------|-----------------|-----------------|
| Word DOCX "Complete" | LibreOffice, pandoc, python-docx, lxml | `/opt/skills/docx/` |
| PowerPoint PPTX | LibreOffice Impress, python-pptx, pptxgenjs, markitdown | `/opt/skills/pptx/` |
| Excel/XLSX | LibreOffice Calc, openpyxl, pandas | `/opt/skills/xlsx/` |
| PDF | qpdf, pdfplumber, pypdf, tesseract-ocr, poppler-utils | — |
| Quick Edits | ffmpeg, ffprobe, Pillow | — |
| Data Analysis & Visualization | pandas, numpy, matplotlib, seaborn, scipy | — |
| YouTube Assistant | No special system deps | — |

## Skills Directory

Skills are embedded in the image at `/opt/skills/` and mounted read-only inside nsjail sandboxes.

```
/opt/skills/
├── docx/
│ ├── SKILL.md
│ └── scripts/
│ ├── accept_changes.py # Accept tracked changes via LibreOffice
│ ├── comment.py # Add/reply comments in unpacked DOCX XML
│ ├── tracked_replace.py # Find-and-replace with redline markup
│ ├── office/
│ │ ├── soffice.py # LibreOffice helper (sandbox-aware)
│ │ ├── unpack.py # Unpack DOCX/PPTX/XLSX to XML
│ │ ├── pack.py # Repack XML to DOCX with validation
│ │ ├── validate.py # XSD + redlining validation
│ │ ├── helpers/
│ │ │ ├── merge_runs.py
│ │ │ └── simplify_redlines.py
│ │ ├── validators/
│ │ │ ├── base.py
│ │ │ ├── docx.py
│ │ │ ├── pptx.py
│ │ │ └── redlining.py
│ │ └── schemas/ # XSD schemas (ISO 29500, ECMA, Microsoft)
│ └── templates/ # XML templates for comments
├── pptx/
│ ├── SKILL.md
│ ├── editing.md # Template-based editing workflow
│ ├── pptxgenjs.md # PptxGenJS tutorial (create from scratch)
│ └── scripts/
│ ├── add_slide.py # Duplicate slide or create from layout
│ ├── clean.py # Remove orphaned slides/media
│ ├── thumbnail.py # Visual thumbnail grid for templates
│ └── office/ → ../../docx/scripts/office (symlink, shared)
└── xlsx/
├── SKILL.md
└── scripts/
├── recalc.py # Formula recalculation via LibreOffice
└── office/
└── soffice.py # LibreOffice helper
```

## Environment Variable

The `SKILLS_ROOT` environment variable is set to `/opt/skills` in all sandbox executions. Agents reference scripts via `$SKILLS_ROOT/docx/scripts/...`.

## System Dependencies Added for Agents

| Package | Purpose | Used By |
|---------|---------|---------|
| `libreoffice-writer` | DOCX conversion, accept tracked changes | Word, XLSX agents |
| `libreoffice-calc` | Formula recalculation | XLSX agent |
| `libreoffice-core`, `libreoffice-common` | Shared LibreOffice runtime | Word, XLSX agents |
| `fonts-liberation`, `fonts-dejavu-core`, `fonts-noto-core` | Document rendering fonts | Word, XLSX, PDF agents |
| `qpdf` | PDF manipulation, linearization, repair | PDF agent |
| `pdfplumber` (Python) | PDF table extraction | PDF agent |
| `pypdf` (Python) | Modern PDF library | PDF agent |
| `docx` (Node.js) | Word document generation from JS | Word agent |
| `markitdown[pptx]` (Python) | PPTX/document to markdown conversion | PPTX agent |
| `pptxgenjs` (Node.js) | PowerPoint generation from JS | PPTX agent |

Already present in base image: `pandoc`, `poppler-utils` (pdftoppm), `tesseract-ocr`, `ffmpeg`, `python-docx`, `python-pptx`, `openpyxl`, `defusedxml`, `matplotlib`, `seaborn`, `pandas`, `numpy`, `scipy`, `Pillow`, `pdf-lib` (Node), `xlsx`/`exceljs` (Node).

## nsjail Sandbox Visibility

The following mounts are added to `docker/nsjail-base.cfg` to make skills and LibreOffice accessible inside sandboxes:

| Host Path | Sandbox Path | Access | Purpose |
|-----------|-------------|--------|---------|
| `/opt/skills` | `/opt/skills` | read-only | Skill scripts |
| `/etc/libreoffice` | `/etc/libreoffice` | read-only | LO configuration |
| `/etc/fonts` | `/etc/fonts` | read-only | Font configuration |
| `/usr/share/fonts` | `/usr/share/fonts` | read-only | Font files |

LibreOffice also needs a writable profile directory; the `soffice.py` helper creates one under `/tmp/` at runtime.

## LibreChat Configuration

Point LibreChat to this instance with these environment variables:

```env
# In LibreChat's .env
LIBRECHAT_CODE_API_KEY=your-api-key-here
LIBRECHAT_CODE_BASEURL=http://your-host:8000
```

## Smoke Tests

Run inside the container:

```bash
docker exec <container> bash /app/tests/smoke/test_agent_skills.sh
```

Tests verify: binary availability, Python/Node package imports, functional DOCX/XLSX/PDF/media operations, skills directory structure, and matplotlib headless rendering.

## tracked_replace.py

Custom implementation for Word tracked changes (redlines). Not part of the upstream Anthropic skill.

Usage:
```bash
python $SKILLS_ROOT/docx/scripts/tracked_replace.py UNPACKED_DIR \
--old "original text" --new "replacement text" \
[--old "another" --new "replacement"] \
[--first] \
[--author "AI-Agent"]
```

Features:
- Proper `<w:del>`/`<w:ins>` XML markup
- Preserves `<w:rPr>` formatting
- Multiple replacement pairs in one pass
- `--first` flag for single occurrence
- Configurable author (default: `AI-Agent`)
- Skips zones already under tracked changes
Loading
Loading