Passa al contenuto principale

Md agent

La classe MdAgent è un layer di manipolazione dei file Markdown (.md). Utilizza markdown-it-py per costruire un indice navigabile delle sezioni del documento (basato sugli heading), ma applica tutte le modifiche direttamente sul testo raw tramite slicing. Questo approccio garantisce che la formattazione originale dell'utente — indentazione, scelte stilistiche (* vs _), spaziatura — venga preservata al 100%.

Costruttore

MdAgent(file_bytes: bytes | None = None, encoding: str = "utf-8")
  • file_bytes (bytes | None): il contenuto binario del file .md. Se None, viene creato un documento vuoto.
  • encoding (str): encoding del file. Default utf-8.

Metodi

save

Restituisce il documento corrente come sequenza di bytes.

save() -> bytes

get_text

Restituisce il testo Markdown raw.

get_text() -> str
suggerimento

Operazione pura: la stringa restituita riflette esattamente lo stato corrente del documento.


get_structure

Restituisce una mappa testuale leggera del documento, mostrando l'albero gerarchico degli heading con i loro indici, livelli e numero di righe di body.

get_structure(preview_len: int = 40) -> str
  • preview_len (int): numero massimo di caratteri per i titoli delle sezioni.

L'output è una stringa con un formato simile a:

MARKDOWN STRUCTURE (4 sections, 20 lines)
────────────────────────────────────────────────────────────
Contains: 1 code blocks, 1 links, 1 images

[0 ] # Intro (19 lines)
[1 ] ## Contesto (12 lines)
[2 ] ### Dettagli (8 lines)
[3 ] ## Conclusioni (2 lines)

L'indentazione visiva riflette il livello dell'heading. I conteggi globali di code block, link e immagini vengono riportati se presenti.

informazioni

Se il documento non contiene heading, viene mostrata un'anteprima del testo. Tutti i restanti metodi che lavorano per indice di sezione restituiscono liste vuote in quel caso.


get_toc

Restituisce la table of contents come lista piatta di dizionari.

get_toc() -> list[dict]

Esempio di output:

[
{"idx": 0, "level": 1, "title": "Intro"},
{"idx": 1, "level": 2, "title": "Contesto"},
{"idx": 2, "level": 3, "title": "Dettagli"},
{"idx": 3, "level": 2, "title": "Conclusioni"},
]

get_section

Restituisce la rappresentazione completa di una sezione, identificata dal suo indice.

get_section(idx: int) -> dict
  • idx (int): indice della sezione (corrisponde all'indice mostrato da get_structure e get_toc).

Il risultato ha questa forma:

{
"idx": 1,
"level": 2,
"title": "Contesto",
"heading_line": "## Contesto",
"content": "Qualche contesto qui. Vedi [il link](...)\n\n### Dettagli\n...",
"raw": "## Contesto\n\nQualche contesto qui...",
"line_start": 4,
"line_end": 16,
"children": [2]
}
  • content contiene tutto il body della sezione (escluso l'heading stesso), incluse eventuali sotto-sezioni.
  • raw contiene heading + body completo.
  • children è la lista degli indici delle sotto-sezioni dirette e indirette contenute nel range.
informazioni

La sezione "termina" dove inizia il prossimo heading di livello uguale o inferiore. Una ## Sezione include quindi tutte le sue ### figlie.


get_code_blocks

Restituisce tutti i blocchi di codice (fenced o indented) presenti nel documento.

get_code_blocks() -> list[dict]

Esempio di output:

[
{
"language": "python",
"code": "def hello():\n print('hi')\n",
"line": 12,
"section_idx": 2
}
]
  • language è la stringa di info del fence (vuota per indented code).
  • section_idx è l'indice della sezione più profonda che contiene il blocco.

Restituisce tutti i link inline [text](url) presenti nel documento.

get_links() -> list[dict]

Esempio di output:

[
{
"text": "il link",
"url": "https://example.com",
"line": 6,
"section_idx": 1
}
]
informazioni

I link reference-style ([text][ref] con definizione separata) non sono attualmente riconosciuti.


get_images

Restituisce tutte le immagini ![alt](url) presenti nel documento.

get_images() -> list[dict]

Esempio di output:

[
{
"alt": "logo",
"url": "logo.png",
"line": 19,
"section_idx": 3
}
]

edit_section

Sostituisce il body di una sezione preservando l'heading originale.

edit_section(idx: int, new_content: str) -> None
  • idx (int): indice della sezione.
  • new_content (str): nuovo contenuto della sezione. Non deve includere l'heading.
warning

Se la sezione conteneva sotto-sezioni (es. una ## Sezione con figlie ###), anche quelle vengono sostituite dal nuovo contenuto. Per modifiche più chirurgiche, agire sulla sotto-sezione specifica.


edit_heading

Modifica titolo e/o livello dell'heading di una sezione.

edit_heading(idx: int, new_title: str, new_level: int | None = None) -> None
  • idx (int): indice della sezione.
  • new_title (str): nuovo titolo (senza i #).
  • new_level (int | None): nuovo livello (1-6). Se None, il livello rimane invariato.
warning

Solleva ValueError se new_level è fuori dal range 1-6.


add_section

Inserisce una nuova sezione nel documento.

add_section(
after_idx: int | None,
level: int,
title: str,
content: str = "",
) -> int
  • after_idx (int | None): la sezione viene inserita dopo questa, alla fine del suo range (incluse le sotto-sezioni). Se None, viene aggiunta in coda al documento.
  • level (int): livello dell'heading (1-6).
  • title (str): titolo della sezione.
  • content (str): contenuto del body (opzionale).

Restituisce l'indice della nuova sezione.

warning

Dopo un add_section o un remove_section, gli indici delle sezioni successive cambiano. È necessario richiamare get_toc o get_structure per ottenere gli indici aggiornati.


remove_section

Rimuove una sezione dal documento.

remove_section(idx: int, recursive: bool = True) -> None
  • idx (int): indice della sezione.
  • recursive (bool): se True (default), rimuove anche tutte le sotto-sezioni. Se False, rimuove solo l'heading e il suo body diretto, lasciando le sotto-sezioni come "orfane" al loro livello originale.

append

Aggiunge testo in coda al documento.

append(text: str) -> None
  • text (str): testo da appendere. Viene preservato così com'è (markdown raw).

prepend

Aggiunge testo in testa al documento.

prepend(text: str) -> None
  • text (str): testo da anteporre. Viene preservato così com'è (markdown raw).

replace

Sostituzione globale stringa-per-stringa nel testo raw.

replace(old: str, new: str, count: int = -1) -> int
  • old (str): stringa da cercare.
  • new (str): stringa di sostituzione.
  • count (int): numero massimo di sostituzioni. -1 significa tutte.

Restituisce il numero di sostituzioni effettuate.

suggerimento

Operazione text-based: utile per refactoring rapidi (es. rinominare un termine in tutto il documento) senza passare per la navigazione strutturata.


Cerca una stringa in tutto il documento, con contesto circostante e localizzazione per riga e sezione.

search(query: str, context_chars: int = 30) -> list[dict]
  • query (str): testo da cercare (case-insensitive).
  • context_chars (int): numero di caratteri di contesto prima e dopo il match.

Restituisce una lista di dizionari:

[
{
"line": 6,
"col": 23,
"section_idx": 1,
"snippet": "…Vedi [**il link**](https://…"
}
]
informazioni

La ricerca non richiede alcun LLM ed è eseguita direttamente sul testo raw.