Choose how to run this agent
Download Agent
Choose how you want to use this agent:
Use Security Settings Key (Recommended)
Use the API key you've already saved in Security Settings. Quick and convenient!
- No need to re-enter API key
- Works offline after download
- Centralized key management
No API key found in Security Settings. Add one now
Enter API Key Manually
Enter your API key now for this specific agent download.
- Use different key for this agent
- One-time use (not saved)
- Works offline after download
Configure Agent Encryption
Description
Freelancer Tax Q&A Helper is a browser-executable AI agent template built on AgentOp. It runs entirely in the browser using Python (via Pyodide) and can be deployed without a server — just download the generated HTML file and open it locally or host it anywhere.
What this agent can do
Freelancer Tax Q&A Helper is built from the Freelancer Tax Q&A Helper template. Runs fully on your own device: llama.cpp compiled to WebAssembly, GPU-accelerated through WebGPU, with no API key and no server. After the one-time model download it works offline. Can run on OpenAI models with your own API key, encrypted in your browser. Can run on Anthropic Claude models with your own API key, encrypted in your browser.
Source Code
# Freelancer Tax Q&A Helper - Python side
# Public functions (no leading underscore) become tools; we expose only process_user_query.
# Do not import heavy packages; keep prompt compact for local models.
from typing import List, Tuple
import asyncio
from textwrap import shorten
import js
# Tunables (use triple-bracket templating with defaults)
MAX_CONTEXT_CHARS = int('[[[MAX_CHARS|6000]]]')
MAX_MEMORY_MESSAGES = 8 # keep it small for local models
# Conversation memory: list of (user, assistant)
HISTORY: List[Tuple[str, str]] = []
SYSTEM_PROMPT = (
"You are a plain-language tax-question helper for freelancers and independent contractors. "
"Answer questions about deductions, quarterly estimated taxes, and self-employment tax. "
"Instructions:\n"
"- Give clear, friendly explanations in simple sentences.\n"
"- Start with a direct answer in 1-2 sentences.\n"
"- Then include: 'Why:' with the general rule.\n"
"- If helpful, add 'How to figure it:' with steps or a small example or quick math.\n"
"- Ask 1-2 clarifying questions if key info is missing.\n"
"- If the user states a jurisdiction, adapt to it. If not, assume U.S. federal rules and note when rules vary by state/country.\n"
"- Do not invent precise statutory citations. You may reference high-level sources like 'IRS Publication 334/535' as examples.\n"
"- If the topic is not tax, politely steer back to freelancer tax topics.\n"
"- Always end with exactly this one-line reminder: This isn't professional tax advice.\n"
"Formatting:\n"
"- Use short paragraphs or bullet points.\n"
"- Show simple calculations clearly.\n"
)
async def _llm_call(prompt: str, system_prompt: str) -> str:
"""Call the injected provider-neutral LLM from Python via JS.
Args:
prompt: The user/context prompt string.
system_prompt: The system instruction string.
"""
# window.callLLM(prompt, systemPrompt) is injected by the platform
try:
resp = await agentop_llm.generate(prompt, system_prompt)
except Exception as e:
return f"Sorry, I couldn't reach the language model service. Please try again. (Error: {e})"
# resp should be a string
try:
return str(resp)
except Exception:
return "Sorry, I couldn't parse the model response. Please try again."
def _reset_state():
"""Reset in-memory conversation state (helper; not exposed as a tool)."""
HISTORY.clear()
def _build_context(jurisdiction: str) -> str:
"""Build textual conversation context limited by character budget.
Args:
jurisdiction: The jurisdiction hint selected by the user.
"""
parts: List[str] = []
jur = jurisdiction.strip() or "US"
parts.append(f"Jurisdiction: {jur}")
parts.append("You are assisting a self-employed freelancer with taxes.")
# Add recent history
if HISTORY:
parts.append("Conversation so far (most recent last):")
for u, a in HISTORY[-MAX_MEMORY_MESSAGES:]:
parts.append(f"User: {u}")
parts.append(f"Assistant: {a}")
context = "\n".join(parts)
# Truncate if needed
if len(context) > MAX_CONTEXT_CHARS:
context = context[-MAX_CONTEXT_CHARS:]
return context
async def process_user_query(query: str, jurisdiction: str = "US") -> str:
"""Handle a user query end-to-end: build context, call the LLM, update memory.
Args:
query: The user's tax question.
jurisdiction: Jurisdiction hint (e.g., 'US', 'UK').
"""
q = (query or "").strip()
if not q:
return "Please enter a freelancer tax question to begin. This isn't professional tax advice."
context = _build_context(jurisdiction)
# Compose final prompt: context + current turn
prompt = (
f"{context}\n\n"
f"User: {q}\n"
f"Assistant:"
)
answer = await _llm_call(prompt, SYSTEM_PROMPT)
# Ensure the mandatory reminder is present (add if missing)
reminder = "This isn't professional tax advice."
if reminder not in answer:
if answer.endswith("."):
answer = f"{answer}\n\n{reminder}"
else:
answer = f"{answer}.\n\n{reminder}"
# Update memory
try:
HISTORY.append((q, answer))
# Trim memory if it grows too large
if len(HISTORY) > MAX_MEMORY_MESSAGES * 2:
del HISTORY[: len(HISTORY) - MAX_MEMORY_MESSAGES]
except Exception:
pass
return answer
More by ozzo
Receipt & Invoice Extractor
Based on the Receipt & Invoice Extractor template.
New Hire Handbook Q&A
Based on the New Hire Handbook Q&A template.
Contract Plain-Language Explainer
Upload a contract and get it explained in plain language — obligations, fees, deadlines, exit claus…
WhatsApp Sales Copilot
Turn a raw WhatsApp chat export into a mini CRM — typed quotes, bookings, payments and boarding pas…
Private Quote & Material Estimator
Drop competing contractor quotes and compare them side by side — totals, inclusions, exclusions — t…
Messy Itinerary Travel Planner
Drop your messy pile of booking PDFs and trip notes and get a clean day-by-day itinerary — plus war…