Using predefined skills
Other tasks may require providing an agent with predefined skills for being able to solve them more efficiently or to solve them at all.
For example, the freeact_skills.zotero.api skill module from the freeact-skills project provides a Python API for syncing Zotero Group libraries with a local directory, loading collection and document metadata as graph into memory and navigating it.
The entire freeact_skills.zotero package is partitioned into a freeact_skills.zotero.api module that provides the Python API, including a definition of domain classes.
This module is presented to code action models so they can understand how to use the Zotero skill.
The freeact_skills.zotero.impl module contains further implementation details that need not be presented to code action models.
The following example demonstrates how a freeact agent uses that skill. It demonstrates how multiple methods and functions from the skill module can be flexibly combined within code actions.
The freeact_skills.zotero.api module is also a good example how domain objects may encapsulate both data and behavior - a core principle of object-oriented programming.
A Collection object, for example, encapsulates data and provides methods sub_documents() and sub_collections() to recursively traverse the collection and document graph under it.
import asyncio
import os
from rich.console import Console
from freeact import CodeActAgent, LiteCodeActModel, execution_environment
from freeact.cli.utils import stream_conversation
async def main():
async with execution_environment(
ipybox_tag="ghcr.io/gradion-ai/ipybox:example",
ipybox_env={
"ZOTERO_API_KEY": os.environ["ZOTERO_API_KEY"],
"ZOTERO_GROUP_ID": os.environ["ZOTERO_GROUP_ID"],
},
) as env:
async with env.code_provider() as provider:
skill_sources = await provider.get_sources(
module_names=["freeact_skills.zotero.api"],
)
async with env.code_executor() as executor:
model = LiteCodeActModel(
model_name="anthropic/claude-3-7-sonnet-20250219",
reasoning_effort="low",
skill_sources=skill_sources,
api_key=os.getenv("ANTHROPIC_API_KEY"),
)
agent = CodeActAgent(model=model, executor=executor)
await stream_conversation(agent, console=Console())
if __name__ == "__main__":
asyncio.run(main())