Skip to content
Skill

Devplacebot

Build persona bots for devplace.net that answer mentions and direct messages through the OpenAI-compatible gateway, generate images, and react with emoji. Use when asked to create, extend, or debug a devplace bot like bot_dolphin_place.py.

Namedevplacebot
Files3 files, 18146 bytes

Instructions

Devplacebot

A devplace bot is a single polling process with three collaborators:
DevPlaceClient (REST), Gateway (LLM), Store (dedupe state). The
reference implementation is bot_dolphin_place.py; the template is
scripts/bot_template.py. Endpoint details: references/api.md.

Architecture

Class Responsibility
Store dataset + SQLite tables seen_notifications, answered_messages, reacted_targets; every table keyed by uid
DevPlaceClient requests.Session with X-API-KEY; get/post raise on HTTP error and return JSON
Gateway OpenAI client with base_url=<base>/openai/v1, same API key, X-App-Reference header
Bot two polls in one loop, each wrapped in a safe runner that logs and continues

Configuration comes from the environment: DEVPLACE_API_KEY
(required), DEVPLACE_BASE_URL (default https://devplace.net).
Model name is molodetz.

Loop

A monotonic scheduler runs poll_mentions every 30 s and
poll_messages every 10 s with a 1 s sleep. No threads. Every poll and
every per-item handler has its own try/except with LOG.exception, so
one bad item never stops the bot or the rest of the batch.

Mentions

  1. GET /notifications returns notification_groups[].entries[]; the
    record is entry["notification"] or the entry itself.
  2. Skip when uid is missing or already in seen_notifications.
  3. Skip and mark seen when read is true.
  4. Only handle types mention, reply, comment.
  5. Mark seen before handling, mark read on the server in finally.
  6. Resolve target_url with the slug regexes for /posts/, /gists/,
    /projects/, /news/, then fetch the detail by slug. The item is
    detail[target_type] or the detail itself.
  7. Content falls back through content, description, source_code,
    title.
  8. Prompt the model with the notification message plus the content,
    post the reply with POST /comments/create (target_uid,
    target_type).
  9. React once per target, recorded in reacted_targets.

Direct messages

  1. GET /messages returns conversations[]; only those with
    unread and other_user.uid.
  2. GET /messages?with_uid=<uid> returns messages[], each
    {is_mine, message: {uid, content}}.
  3. Answer only when the last incoming message uid is not in
    answered_messages; mark it answered before calling the model.
  4. History is the last 20 messages, is_mine mapped to assistant,
    others to user, empty content dropped.
  5. Append a line to the system prompt stating this is a private chat.
  6. Reply with POST /messages/send (receiver_uid).

Persona

The persona is the INSTRUCTIONS system prompt. Keep these sections:

Image protocol

The model requests an image by ending its reply with exactly one line
IMAGE: <visual description>. split_image_request inspects only the
last line, case-insensitive, and returns (reply, prompt). The prompt
goes to POST /uploads/generate-image; the returned uid is sent as
attachment_uids on the comment or message. The system prompt must
state that the line is added only on explicit request and is never
mentioned to the user. Image failure is logged and the text reply still
goes out.

Reactions

A separate completion with the persona prompt asks for exactly one emoji
or NONE. Accept only the first line, reject empty, NONE, or longer
than 8 characters. Send via POST /reactions/<type>/<uid> with the
X-Requested-With: fetch header.

Delivery semantics

State is marked before the side effect. A failure therefore drops one
reply instead of looping and spamming; this is deliberate. Keep that
order. Do not mark after success unless duplicate replies are
acceptable.

Extending

Checklist

Files

Download ZIP

43.0ms