Hopp til innholdet

DocumentationPixel, the team agentMarkdown

Pixel, the team agent

Pixel is the AI assistant inside the panel for the tenant's own staff (admins and agents), the same staff assistant as in Sevenfold's other apps. It follows Snakkbar's look: its face is the Snakkbar bubble. Staff chat with it to write and improve newsletters, find content on their website, check who a campaign goes to, and read results. The website assistant talks to customers; Pixel talks to the team. (Pixel is a different assistant: the snakkbar tenant's own, for visitors on snakkbar.app.)

Its tools cover the overview and numbers, conversations with customers (read only), answer quality and knowledge, callbacks, who is on the site, the website assistant's settings (changes need a person's approval), and Mailbar. Asked about other parts of Snakkbar (people and roles, departments, notifications, webhooks, API keys, the chat's look), it says where in the panel to go.

What it can do

It works through tools on the tenant's own data, as the signed-in person. Changing the website assistant's settings is for admins only; with an agent, Pixel shows them and says an admin must change them:

ToolWhat it does
list_campaigns, get_campaignRead campaigns: fields, blocks, sender, recipient count, and what is missing before sending
create_campaign, update_campaignWrite drafts. Blocks are validated like the editor's (campaigns.md); only drafts can change
list_lists, count_recipientsE-mail lists with subscriber counts, and how many a send would reach
search_website, read_web_pageThe tenant's site: products, news and pages (titles, descriptions, links, images), the same search the website assistant uses
send_test_to_meA test of a campaign to the operator's own address only
campaign_resultsDelivered, opened (indicative), clicked, visited, unsubscribed, bounced, and clicks per link
rememberA note about the tenant for later conversations (tone, sign-off, lists to use)
get_template, update_templateMailbar's template («Mal»): the design every mail gets and the blocks new campaigns start from (campaigns.md)
create_listA new, empty e-mail list
overviewOversikt's numbers for 1, 7, 30 or 90 days: visitors, conversations, how many a person took, response time, pages, answer quality
find_conversations, read_conversationSearch or list conversations with customers, and read one (it never writes to customers)
quality_queueAnswers to look at: thumbs down, nothing found, low ratings, handoffs
knowledge_overview, search_knowledgeWhat the knowledge base holds, and what the website assistant would find for up to ten questions at once
suggest_knowledgeA question and answer for the knowledge base, pending until a person approves it under Kunnskap → Forslag
knowledge_candidatesIn one call: the pending suggestions (made from staff replies to customers, often raw and duplicated) and the questions the assistant could not answer that nobody did (e-mail addresses and phone numbers masked)
rewrite_suggestionsRewrites pending suggestions into proper articles (general question, complete answer, no personal details); they stay pending
reject_suggestionsRejects pending suggestions (merged duplicates, one customer's matter, small talk), after the operator approves
list_callbacks, mark_callback_handledCallback requests, and marking one done when the user says so
live_visitorsWho is on the site now (page, where from, device, place)
get_assistant_settingsThe website assistant's name, tone, instructions, topics to avoid, welcome, suggestions, opening hours, callbacks; the team, departments and saved replies
update_assistant_settingsChanges to those settings, after the operator approves them in the panel (below)

Pictures. Staff paste, drop or attach images in Pixel's composer (up to six a message). They are uploaded first (POST /operator/campaign-images) and sent with the message; the model sees them, so a screenshot of a newsletter or the website becomes a template in that style, and the images can go straight into image blocks. With «Mal» open the panel says so (template: true).

It never sends, schedules or deletes anything, and cannot unsubscribe or erase contacts: those stay a person's click in the panel. It never writes to customers either.

Conversations into knowledge. Asked to go through conversations or the suggestions, Pixel takes everything at once (knowledge_candidates), groups it by topic, checks the topics against the knowledge base, rewrites the best suggestion per topic into an article (merging duplicates), asks to reject the rest, and lists questions nobody has answered for the team. It never approves: articles reach the website assistant only when a person approves them under Kunnskap → Forslag.

Templates and newsletters. A new newsletter builds on the template: with named sections (slot) Pixel gives only each section's content (create_campaign with sections), and the server puts it into the template, so fixed blocks, styles and columns stay exactly as designed. Asked for a template after a model (a screenshot, a link to a newsletter's web version, the website), Pixel hands it to its template designer (pixel/agent/subagents/maldesigner, Opus): a subagent with a small VM of its own (Vercel Sandbox, a headless Chromium prepared once per deploy). It looks at the screenshots, takes a screenshot of the link or the site and reads the newsletter's HTML for exact colours and fonts, builds the template from Mailbar's blocks, draws it (desktop and phone) and corrects it two or three times, and returns it; Pixel saves it with update_template.

Long turns. One API request follows a turn for at most four minutes (the route's limit is five). A turn still running then goes on in eve: the request ends with a continue event and the turn is stored as agent_threads.pending (where its stream starts and the transcript before it). The panel follows it with POST /operator/agent/threads/:id/resume, which replays it from its start; a thread opened while that is so says working and is followed the same way; the knowledge review's cron finishes turns nobody followed. A turn is stopped after 15 minutes in all.

Scheduled review. Under Innstillinger → Assistentene → Pixel an admin picks how often Pixel does this on its own: off (default), every week, every other week or every month (tenants.knowledge_review). An hourly cron (/internal/knowledge-review, server/knowledge-review.ts) runs one due tenant at a time between 06 and 10 Norwegian time: a new Pixel conversation of the admin who turned it on (else the first admin), titled «Kunnskapsgjennomgang ». Rejections in it wait for that admin's approval there; articles wait under Kunnskap → Forslag as usual.

Approval. A change to what the website assistant tells visitors waits for the operator: the tool has eve's approval: always(), so the turn parks before it runs (also for rejecting suggestions, which then leave Kunnskap → Forslag). The panel shows the change field by field (the new value, the current one behind «Vis nåværende») with «Godkjenn» and «Avvis»; the answer resumes the same turn. Writing something else instead drops the change. Settings are checked against the same rules as Innstillinger (server/tenant-settings.ts). It writes in Norwegian, uses real pages and images from the site, and never invents products, prices or offers.

Conversations

A conversation (thread) belongs to the operator who started it. One answer runs at a time per thread. When a campaign is open in the panel, the panel sends its id, and "the campaign" means that one; changes Pixel makes show up in the editor right away. Notes it remembers are shared by the tenant's admins and listed under Innstillinger → Assistentene → Pixel, where they can be deleted.

Model calls are metered on the tenant (agent_turns, agent_cost_usd), and stop at the tenant's daily AI cost ceiling. Each operator can send 120 messages an hour.

How it runs

Pixel is an eve agent of its own in pixel/agent/ (tools in pixel/agent/tools/, the standing rules in instructions.md, and per turn who it works for, what the panel has open and its memories in instructions/denne-samtalen.ts). It sits beside the website assistant (agent/), so its tools never exist in a visitor's session. next.config.ts mounts both: the website assistant at /eve/kundechat/v1, Pixel at /eve/pixel/v1.

The API is Pixel's only caller (server/team-agent.ts): it checks the panel sign-in, then sends the turn with the internal secret, the tenant, operator and thread, and what is open in the panel (pixel/agent/channels/eve.ts). Tools check the operator again on every call (on the tenant's team and not deactivated; an admin for the assistant's settings). Each thread is one eve session (agent_threads.eve_session_id), which keeps the model's history and compacts it when it grows; the API keeps the transcript the panel shows, and translates eve's stream into the panel's events below. A turn is capped at 16 model calls and $2, a session at $25.

Evals. npm run eval:pixel runs Pixel's evals (pixel/evals/) on a local dev server as an admin of EVAL_TENANT (default amatec), with its real campaigns, lists, template and site; tools that write are stubbed. EVAL_MODEL=<gateway id> tries another model. Needs pixel/.env.local (a copy of the root one).

API (anyone on the team, /api/v1; the memories are for admins)

Method and pathBody / result
GET /operator/agent→ { name, threads: { id, title, createdAt, updatedAt, busy }[] }
POST /operator/agent/threads→ { thread } (201)
GET /operator/agent/threads/:id→ { thread: { …, transcript } }: the operator's and Pixel's messages, with the tools each answer used
DELETE /operator/agent/threads/:id→ 204
POST /operator/agent/threads/:id/messages{ text, campaignId?, template?, images? } (images: up to six URLs from POST /operator/campaign-images) → text/event-stream: text { delta }, tool { name, label, state }, campaign { campaignId, created }, template (the template changed: reload it), approval { approval } (a change waits for the operator; the item in done carries it), then done { item } or error { code, message }. 409 while another answer runs or when the daily AI limit is reached.
POST /operator/agent/threads/:id/approval{ requestId, approve } → the same stream as a message, as the turn goes on. 409 when the change no longer waits.
POST /operator/agent/threads/:id/resumeFollows a turn that outlived its request (after continue, or a thread with working): reset, then the turn from its start, then done (or continue again). 409 when nothing is going on. A new message while a turn goes on is 409.
GET /operator/agent/memories→ { memories: { id, text, createdAt }[] }
DELETE /operator/agent/memories/:id→ 204