Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/docker-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ name: Build and Publish Docker Image

on:
push:
tags: ["llamagram@v*.*.*"]
branches: [main]
# tags: ["lobsterx@v*.*.*"]
branches: [master] # avoid publishing for the first time

env:
REGISTRY: ghcr.io
IMAGE_NAME: astrabert/llamagram
IMAGE_NAME: astrabert/lobsterx

jobs:
build-and-publish-docker-image:
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:
id: build-and-push
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
with:
context: packages/llamagram
context: packages/lobsterx
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
shell: bash
run: make lint-check

lint-llamagram:
lint-lobsterx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -37,9 +37,9 @@ jobs:
- name: Run formatter
shell: bash
run: make format-check
working-directory: packages/llamagram
working-directory: packages/lobsterx

- name: Run linter
shell: bash
run: make lint-check
working-directory: packages/llamagram
working-directory: packages/lobsterx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: GitHub Release LlamaGram
name: GitHub Release LobsterX

on:
push:
tags:
- "llamagram@v[0-9].[0-9]+.[0-9]+*"
- "lobsterx@v[0-9].[0-9]+.[0-9]+*"

jobs:
release-mcp:
Expand All @@ -20,14 +20,14 @@ jobs:

- name: Build
run: uv build -o dist
working-directory: packages/llamagram
working-directory: packages/lobsterx

- name: Publish to PyPI
run: uv publish --token ${{ secrets.PYPI_TOKEN }}
working-directory: packages/llamagram
working-directory: packages/lobsterx

- name: Create GitHub Release
uses: ncipollo/release-action@v1
with:
artifacts: "packages/llamagram/dist/*"
artifacts: "packages/lobsterx/dist/*"
generateReleaseNotes: true
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Run Tests on Main Package
run: make test

testing_pr_llamagram:
testing_pr_lobsterx:
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -41,4 +41,4 @@ jobs:

- name: Run Tests on Main Package
run: make test
working-directory: packages/llamagram
working-directory: packages/lobsterx
4 changes: 2 additions & 2 deletions .github/workflows/typecheck.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Run ty
run: make typecheck

core-typecheck-llamagram:
core-typecheck-lobsterx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -35,4 +35,4 @@ jobs:

- name: Run ty
run: make typecheck
working-directory: packages/llamagram
working-directory: packages/lobsterx
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ wheels/

# caches
*_cache/
.llamagram/
.lobsterx/
# memory jsonl file
.agent_memory.jsonl

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Contributing to `workflows-acp` and `llamagram`
# Contributing to `workflows-acp` and `lobsterx`

Thank you for your interest in contributing to this project! Please review these guidelines before getting started.

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,11 @@ def main() -> None:
)
```

## LlamaGram
## LobsterX

[LlamaGram](./packages/llamagram) is the [OpenClaw](https://openclaw.ai)-like AI agent (working as a Telegram bot) for document processing based on the `workflows-acp` harness and on [LlamaCloud](https://cloud.llamaindex.ai).
[LobsterX](./packages/lobsterx) is the [OpenClaw](https://openclaw.ai)-like AI agent (working as a Telegram bot) for document processing based on the `workflows-acp` harness and on [LlamaCloud](https://cloud.llamaindex.ai).

Find more in the [dedicated README](./packages/llamagram/README.md)
Find more in the [dedicated README](./packages/lobsterx/README.md)

## License

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ USER user
ENV PATH=/home/user/.local/bin:$PATH
WORKDIR /home/user/workspace

# Install llamagram
RUN uv tool install llamagram --prerelease=allow
# Install lobsterx
RUN uv tool install lobsterx --prerelease=allow

CMD [ "llamagram", "run" ]
CMD [ "lobsterx", "run" ]
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/llamagram/Makefile → packages/lobsterx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ format-check:

typecheck:
$(info ****************** type checking ******************)
uv run ty check src/llamagram/
uv run ty check src/lobsterx/

build:
$(info ****************** building ******************)
Expand Down
54 changes: 27 additions & 27 deletions packages/llamagram/README.md → packages/lobsterx/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# LlamaGram
# LobsterX

LlamaGram is an AI agent inspired by [OpenClaw](https://openclaw.ai) (formerly known as MoltBot or ClawdBot), which focuses on document-related tasks.
LobsterX is an AI agent inspired by [OpenClaw](https://openclaw.ai) (formerly known as MoltBot or ClawdBot), which focuses on document-related tasks.

It runs as a Telegram bot as comes with a CLI interface to set up the necessary environment variables.

## Prerequisites

- Python (if setting up the bot natively, preferably with `uv`) or Docker (if deploying with Docker)
- A Telegram Bot Token, in order to connect to Telegram. Follow [this guide](https://core.telegram.org/bots/tutorial) on how to create your Telegram bot with BotFather.
- A LlamaCloud API key, in order to give LlamaGram document-processing capabilities. Sign up on LlamaCloud [here](https://cloud.llamaindex.ai/signup).
- A LlamaCloud API key, in order to give LobsterX document-processing capabilities. Sign up on LlamaCloud [here](https://cloud.llamaindex.ai/signup).
- An API key for Google, OpenAI or Anthropic (you can choose one among the three or swap between different providers)

## Installation
Expand All @@ -17,71 +17,71 @@ Install the bot natively:

```bash
# uv (recommended)
uv tool install llamagram --prerelease=allow
uv tool install lobsterx --prerelease=allow
# pip
pip install llamagram
pip install lobsterx
```

Pull the docker image (only works for AMD64-compatible platforms):

```bash
docker pull ghcr.io/astrabert/llamagram:main
docker pull ghcr.io/astrabert/lobsterx:main
```

## Setup

Through environment variables, you can customize the setup of LlamaGram:
Through environment variables, you can customize the setup of LobsterX:

- `LLAMAGRAM_LLM_PROVIDER`: LLM provider (choose between `google`, `anthropic` and `openai`). Default is `openai`
- `LLAMAGRAM_LLM_MODEL`: LLM model (choose among [available models](../../README.md#available-llm-models)). Default is `gpt-4.1`
- `LOBSTERX_LLM_PROVIDER`: LLM provider (choose between `google`, `anthropic` and `openai`). Default is `openai`
- `LOBSTERX_LLM_MODEL`: LLM model (choose among [available models](../../README.md#available-llm-models)). Default is `gpt-4.1`

You then need to set three required env variables:

- `LLAMAGRAM_LLM_API_KEY`: API key for the LLM (you can also use `OPENAI_API_KEY`, `GOOGLE_API_KEY` or `ANTHROPIC_API_KEY`, depending on the provider).
- `LOBSTERX_LLM_API_KEY`: API key for the LLM (you can also use `OPENAI_API_KEY`, `GOOGLE_API_KEY` or `ANTHROPIC_API_KEY`, depending on the provider).
- `TELEGRAM_BOT_TOKEN`: token for the Telegram bot
- `LLAMA_CLOUD_API_KEY`: API key for LlamaCloud

You can use the setup wizard to configure LlamaGram interactively on the terminal:
You can use the setup wizard to configure LobsterX interactively on the terminal:

```bash
llamagram setup --interactive
lobsterx setup --interactive
```

Or pass options from CLI:

```bash
llamagram setup --provider google \
lobsterx setup --provider google \
--model gemini-3-flash-preview \
--api-key $GOOGLE_API_KEY \
--llama-cloud-key $LLAMA_CLOUD_API_KEY \
--telegram-token $TELEGRAM_BOT_TOKEN
```

This will create a `.env` file with the necessary variables, which will be loaded by LlamaGram at runtime (make sure not to share it with anyone).
This will create a `.env` file with the necessary variables, which will be loaded by LobsterX at runtime (make sure not to share it with anyone).

## Run

Run LlamaGram as a CLI app:
Run LobsterX as a CLI app:

```bash
llamagram run
lobsterx run
```

You can set the `--log-level` option, if you wish to have more or less logging.

Run LlamaGram in a Docker container referencing a `.env` file:
Run LobsterX in a Docker container referencing a `.env` file:

```bash
docker run ghcr.io/astrabert/llamagram:main --env-file=".env"
docker run ghcr.io/astrabert/lobsterx:main --env-file=".env"
```

Or, setting env varaibles directly (not recommended):

```bash
docker run ghcr.io/astrabert/llamagram:main \
--env="LLAMAGRAM_LLM_PROVIDER=openai" \
--env="LLAMAGRAM_LLM_MODEL=gpt-4.1"\
--env="LLAMAGRAM_LLM_API_KEY=sk-xxx" \
docker run ghcr.io/astrabert/lobsterx:main \
--env="LOBSTERX_LLM_PROVIDER=openai" \
--env="LOBSTERX_LLM_MODEL=gpt-4.1"\
--env="LOBSTERX_LLM_API_KEY=sk-xxx" \
--env="LLAMA_CLOUD_API_KEY=llx-xxx" \
--env="TELEGRAM_BOT_TOKEN=tok-xxx"
```
Expand All @@ -95,17 +95,17 @@ When on Telegram, you can perform two actions:

> _With `/start` command, you will have a welcome message explaining how to use the bot_

## How LlamaGram Works
## How LobsterX Works

LlamaGram is a generalist AI agent based on three main principles:
LobsterX is a generalist AI agent based on three main principles:

- [LlamaIndex Agent Workflows](https://github.com/run-llama/workflows-py): a powerful workflow engine that allows event-driven, stepwise execution of specific tasks and functions. LlamaGram uses a cyclic workflow to go through thinking, tool-calling and observing repeatedly until it produces its final output.
- [LlamaIndex Agent Workflows](https://github.com/run-llama/workflows-py): a powerful workflow engine that allows event-driven, stepwise execution of specific tasks and functions. LobsterX uses a cyclic workflow to go through thinking, tool-calling and observing repeatedly until it produces its final output.
- Structured outputs: the LLM underlying the agent is forced to produce JSON outputs that comply with certain schemas (a tool call, a thought, an observation...): outputs are produced informed by the previous chat history, and based on context about available tools and specific tasks the agent has to perform.
- Security by design: the agent does not have access to your real filesystem, but it does have access to a virtualized copy of it provided through [AgentFS](https://github.com/tursodatabase/agentfs). PDFs sent over Telegram are also not downloaded into your real filesystem, but written within AgentFS. Files such as `.env`s or other popular credential files (`.npmrc`, `.pypirc`, `.netrc`) are excluded from the virtual filesystem, and thus unaccessible to the agent. The agent cannot use bash commands (it has access to filesystem-based tools like read/write/edit/grep/glob for AgentFS) to avoid it being able to perform destructive or vulnerable operations.

Here is what happens when you send a prompt to LlamaGram:
Here is what happens when you send a prompt to LobsterX:

![Flowchart LlamaGram](./assets/flowchart_llamagram.png)
![Flowchart LobsterX](./assets/flowchart_lobsterx.png)

Along with the final response, the agent will also send you a report of everything it did during its session as a markdown file (namedd `session-<random-id>-report.md`).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["uv_build>=0.9.10,<0.10.0"]
build-backend = "uv_build"

[project]
name = "llamagram"
name = "lobsterx"
version = "0.1.0-beta"
description = "Background AI assistant working as a Telegram bot, built specifically for document-related use cases"
readme = "README.md"
Expand Down Expand Up @@ -31,4 +31,4 @@ dev = [
]

[project.scripts]
llamagram = "llamagram.cli:app"
lobsterx = "lobsterx.cli:app"
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ def setup_wizard(
) -> None:
if interactive:
llm_provider = Prompt().ask(
"LLM Provider for LlamaGram",
"LLM Provider for LobsterX",
choices=["openai", "google", "anthropic"],
show_choices=True,
) # type: ignore
llm_model = Prompt().ask(
"LLM Model for LlamaGram",
"LLM Model for LobsterX",
choices=[
m
for m in list(AVAILABLE_MODELS.keys())
Expand All @@ -102,8 +102,8 @@ def setup_wizard(
dot_env = Path(".env")
if not dot_env.exists():
dot_env.touch()
set_key(".env", key_to_set="LLAMAGRAM_LLM_PROVIDER", value_to_set=llm_provider)
set_key(".env", key_to_set="LLAMAGRAM_LLM_MODEL", value_to_set=llm_model)
set_key(".env", key_to_set="LLAMAGRAM_LLM_API_KEY", value_to_set=api_key)
set_key(".env", key_to_set="LOBSTERX_LLM_PROVIDER", value_to_set=llm_provider)
set_key(".env", key_to_set="LOBSTERX_LLM_MODEL", value_to_set=llm_model)
set_key(".env", key_to_set="LOBSTERX_LLM_API_KEY", value_to_set=api_key)
set_key(".env", key_to_set="LLAMA_CLOUD_API_KEY", value_to_set=llama_cloud_api_key)
set_key(".env", key_to_set="TELEGRAM_BOT_TOKEN", value_to_set=telegram_token)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class FileContentCache:
def __init__(self) -> None:
self._cache = DiskCache(directory=".llamagram/cache")
self._cache = DiskCache(directory=".lobsterx/cache")
self._ttl: float = 60 * 60 * 24 # one day

async def set(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@


def start(user: User | None) -> str:
greetings = "Hello there, Llama Enthusiast!"
greetings = "Hello there, Lobster Enthusiast!"
if user is not None and user.username is not None:
username = user.username
if not username.startswith("@"):
Expand All @@ -45,7 +45,7 @@ def start(user: User | None) -> str:

return f"""
{greetings}
I am LlamaGram, your personal assistant for whatever concerns documents.
I am LobsterX, your personal assistant for whatever concerns documents.
I can navigate the filesystem from the directory where you deployed me, and perform operations based on your text messages.
You can also upload PDF documents from this chat, that I will download and will be able to use afterwards.
With this being said, please, ask any questions you like!
Expand All @@ -55,13 +55,13 @@ def start(user: User | None) -> str:
@functools.lru_cache(maxsize=1)
def get_llm() -> LLMWrapper:
load_dotenv()
llm_provider = os.getenv("LLAMAGRAM_LLM_PROVIDER", "openai")
llm_provider = os.getenv("LOBSTERX_LLM_PROVIDER", "openai")
if llm_provider not in ("openai", "google", "anthropic"):
raise ValueError(f"Unsupported model provider: {llm_provider}")
model = os.getenv("LLAMAGRAM_LLM_MODEL", DEFAULT_MODEL[llm_provider])
model = os.getenv("LOBSTERX_LLM_MODEL", DEFAULT_MODEL[llm_provider])
if AVAILABLE_MODELS.get(model) != llm_provider:
raise ValueError(f"Unsupported model for provider {llm_provider}: {model}")
api_key = os.getenv("LLAMAGRAM_LLM_API_KEY") or os.getenv(
api_key = os.getenv("LOBSTERX_LLM_API_KEY") or os.getenv(
f"{llm_provider.upper()}_API_KEY"
)
if api_key is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
from pathlib import Path

import pytest

from llamagram.tools.caching import FileContentCache
from lobsterx.tools.caching import FileContentCache


def test_cache_setup(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.chdir(tmp_path)
cache = FileContentCache()
assert cache._ttl == 60 * 60 * 24
assert (tmp_path / ".llamagram" / "cache").is_dir()
assert (tmp_path / ".lobsterx" / "cache").is_dir()


@pytest.mark.asyncio
Expand Down
Loading