Tool

Edit Artifacts with LLM-Powered JSON Patching

LlamaIndex tool letting an agent create and iteratively edit a structured, Pydantic-modeled artifact in-memory.

Works with openaipydantic

81
Spark score
out of 100
Updated 2 days ago
Version 0.14.23

Add to Favorites

Why it matters

Empower LLMs and agents to programmatically create, modify, and iterate on complex artifacts like reports and code using Pydantic models and JSON patch operations.

Outcomes

What it gets done

01

Define artifact structure using Pydantic models.

02

Apply JSON patch operations for in-memory artifact editing.

03

Integrate with LLM agents for iterative content generation.

04

Store and inject artifacts into agent memory.

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/li-tool-tools-artifact-editor | bash

Overview

Artifact Editor Tool Spec

ArtifactEditorToolSpec lets an agent create and iteratively edit a Pydantic-modeled artifact (a report, code, or similar structured content) in-memory using JSON patch operations, with ArtifactMemoryBlock keeping the artifact in the agent's memory across turns. Use it when an agent needs to build and revise a structured document over a multi-turn conversation. It requires modeling the artifact's shape as a Pydantic model.

What it does

ArtifactEditorToolSpec is a stateful tool spec that lets an agent edit an artifact in-memory using JSON patch operations. An LLM/Agent can be prompted to create, modify, and iterate on an artifact -- a report, code, or anything representable as a Pydantic model -- and the current state is retrievable via the tool spec's get_current_artifact() method. The package also includes ArtifactMemoryBlock, which stores the artifact and injects it into the LLM/Agent's memory so it stays available across turns.

When to use - and when NOT to

Use it when you want an agent to build and iteratively edit a structured document over a multi-turn conversation -- for example generating a report made of text, table, and image blocks, then asking the agent to rearrange or revise specific parts of it. It is built around Pydantic models representing the artifact's structure, so it is not a fit for freeform or unstructured content that does not map cleanly to a schema.

Inputs and outputs

Install with:

pip install llama-index-tools-artifact-editor

Define the artifact's shape as a Pydantic model -- the example uses a Report made of TextBlock (a content string), TableBlock (headers and rows), and ImageBlock (an image_url) variants -- then wire it into an agent:

tool_spec = ArtifactEditorToolSpec(Report)
tools = tool_spec.to_tool_list()

memory = Memory.from_defaults(
    session_id="artifact_editor_01",
    memory_blocks=[ArtifactMemoryBlock(artifact_spec=tool_spec)],
    token_limit=60000,
    chat_history_token_ratio=0.7,
)

agent = FunctionAgent(
    tools=tools,
    llm=OpenAI(model="o3-mini"),
    system_prompt="You are an expert in writing reports. When you write a report, I will be able to see it (and also any changes you make to it!), so no need to repeat it back to me once its written.",
)

The example configures Memory with a 60,000-token limit and a 0.7 chat-history-to-artifact token ratio, controlling how much of that budget goes to conversation history versus the artifact itself. From there, a chat loop (typing "exit" or "quit" to stop) lets you prompt the agent -- "Create a ficticous report about the history of the internet," then "Move the image to the top of the report" -- while streaming the response as it's generated and printing which tool is called with what arguments as the artifact is edited. The artifact itself updates in-memory each turn, accessible via tool_spec.get_current_artifact().

Who it's for

Developers building agents that need to produce and iteratively revise a structured document -- reports, code, or any Pydantic-modeled content -- over a conversation, rather than regenerating the whole thing from scratch on every edit.

Source README

Artifact Editor Tool Spec

pip install llama-index-tools-artifact-editor

The ArtifactEditorToolSpec is a stateful tool spec that allows you to edit an artifact in-memory.

Using JSON patch operations, an LLM/Agent can be prompted to create, modify, and iterate on an artifact like a report, code, or anything that can be represented as a Pydantic model.

The tool package also includes an ArtifactMemoryBlock that can be used to store the artifact and inject it into the LLM/Agent's memory.

Usage

Below is an example of how to use the ArtifactEditorToolSpec and ArtifactMemoryBlock to create and iterate on a report.

import asyncio
from pydantic import BaseModel, Field
from typing import List, Literal, Optional, Any

from llama_index.core.agent.workflow import (
    FunctionAgent,
    AgentStream,
    ToolCallResult,
)
from llama_index.core.memory import Memory
from llama_index.tools.artifact_editor import (
    ArtifactEditorToolSpec,
    ArtifactMemoryBlock,
)
from llama_index.llms.openai import OpenAI

### Define the Artifact Pydantic Model


class TextBlock(BaseModel):
    type: Literal["text"] = "text"
    content: str = Field(description="The content of the text block")


class TableBlock(BaseModel):
    type: Literal["table"] = "table"
    headers: List[str] = Field(description="The headers of the table")
    rows: List[List[str]] = Field(description="The rows of the table")


class ImageBlock(BaseModel):
    type: Literal["image"] = "image"
    image_url: str = Field(description="The URL of the image")


class Report(BaseModel):
    """Creates an instance of a report, which is a collection of text, tables, and images."""

    title: str = Field(description="The title of the report")
    content: List[TextBlock | TableBlock | ImageBlock] = Field(
        description="The content of the report"
    )


### Initialize the tool spec and tools
tool_spec = ArtifactEditorToolSpec(Report)
tools = tool_spec.to_tool_list()

### Initialize the memory
memory = Memory.from_defaults(
    session_id="artifact_editor_01",
    memory_blocks=[ArtifactMemoryBlock(artifact_spec=tool_spec)],
    token_limit=60000,
    chat_history_token_ratio=0.7,
)

### Create the agent
agent = FunctionAgent(
    tools=tools,
    llm=OpenAI(model="o3-mini"),
    system_prompt="You are an expert in writing reports. When you write a report, I will be able to see it (and also any changes you make to it!), so no need to repeat it back to me once its written.",
)


### Run the agent in a basic chat loop
### As it runs, the artifact will be updated in-memory and
### can be accessed via the `get_current_artifact` method.
async def main():
    while True:
        user_msg = input("User: ").strip()
        if user_msg.lower() in ["exit", "quit"]:
            break

        handler = agent.run(user_msg, memory=memory)
        async for ev in handler.stream_events():
            if isinstance(ev, AgentStream):
                print(ev.delta, end="", flush=True)
            elif isinstance(ev, ToolCallResult):
                print(
                    f"\n\nCalling tool: {ev.tool_name} with kwargs: {ev.tool_kwargs}"
                )

        response = await handler
        print(str(response))
        print("Current artifact: ", tool_spec.get_current_artifact())


if __name__ == "__main__":
    asyncio.run(main())

When running this, you might initially ask the agent:

User: Create a ficticous report about the history of the internet

And you will get a report with a list of blocks. Try asking it to modify the report!

User: Move the image to the top of the report

And you will get a report with the image moved to the top.

Check out the documentation for more example on agents, memory, and tools.

FAQ

Common questions

Discussion

Questions & comments · 0

Sign In Sign in to leave a comment.