thepopebot 1.2.75-beta.12 → 1.2.75-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,13 +4,9 @@
4
4
  // Paths ending with '/' are directories (all contents are managed).
5
5
  export const MANAGED_PATHS = [
6
6
  '.github/workflows/',
7
-
8
7
  'docker-compose.yml',
9
8
  '.dockerignore',
10
9
  '.gitignore',
11
- 'agent-job/CLAUDE.md',
12
- 'event-handler/CLAUDE.md',
13
- 'skills/CLAUDE.md',
14
10
  ];
15
11
 
16
12
  export function isManaged(relPath) {
package/lib/ai/index.js CHANGED
@@ -385,7 +385,7 @@ async function autoTitle(threadId, firstMessage) {
385
385
 
386
386
  const model = await createModel({ maxTokens: 250 });
387
387
  const response = await model.withStructuredOutput(z.object({ title: z.string() })).invoke([
388
- ['system', 'Generate a descriptive (8-12 word) title for this chat based on the user\'s first message.'],
388
+ ['system', 'Title this chat in 2-5 words. Name the subject matter only. Never start with "User". Never describe what the user is doing — just the topic. Always produce a title, even for vague messages — infer the likely topic.'],
389
389
  ['human', firstMessage],
390
390
  ]);
391
391
  if (response.title.trim()) {
package/lib/chat/api.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { auth } from '../auth/index.js';
2
2
  import { chatStream } from '../ai/index.js';
3
3
  import { v4 as uuidv4 } from 'uuid';
4
+ import { getConfig } from '../config.js';
4
5
 
5
6
  /**
6
7
  * POST handler for /stream/chat — streaming chat with session auth.
@@ -114,11 +115,26 @@ export async function POST(request) {
114
115
  toolCallId: chunk.toolCallId,
115
116
  toolName: chunk.toolName,
116
117
  });
118
+ // Enrich coding_agent input with active agent identity from config
119
+ let input = chunk.args;
120
+ if (chunk.toolName === 'coding_agent') {
121
+ const agent = getConfig('CODING_AGENT') || 'claude-code';
122
+ const providerKeys = {
123
+ 'claude-code': 'CODING_AGENT_CLAUDE_CODE_BACKEND',
124
+ 'pi-coding-agent': 'CODING_AGENT_PI_PROVIDER',
125
+ 'gemini-cli': 'CODING_AGENT_GEMINI_CLI_PROVIDER',
126
+ 'codex-cli': 'CODING_AGENT_CODEX_CLI_PROVIDER',
127
+ 'opencode': 'CODING_AGENT_OPENCODE_PROVIDER',
128
+ 'kimi-cli': 'CODING_AGENT_KIMI_CLI_PROVIDER',
129
+ };
130
+ const backendApi = getConfig(providerKeys[agent]) || 'anthropic';
131
+ input = { ...chunk.args, codingAgent: agent, backendApi };
132
+ }
117
133
  writer.write({
118
134
  type: 'tool-input-available',
119
135
  toolCallId: chunk.toolCallId,
120
136
  toolName: chunk.toolName,
121
- input: chunk.args,
137
+ input,
122
138
  });
123
139
 
124
140
  } else if (chunk.type === 'tool-result') {
@@ -150,12 +150,19 @@ function ToolCall({ part, className }) {
150
150
  /* @__PURE__ */ jsx(WrenchIcon, { size: 14, className: "text-muted-foreground shrink-0 mt-0.5" }),
151
151
  /* @__PURE__ */ jsx("span", { className: "flex flex-col min-w-0 flex-1", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
152
152
  /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: displayName }),
153
- isDone && (() => {
153
+ (() => {
154
154
  try {
155
- const o = typeof part.output === "string" ? JSON.parse(part.output) : part.output;
156
- const meta = Array.isArray(o) ? o.find((e) => e.type === "meta") : o;
157
- if (meta?.codingAgent || meta?.backendApi) {
158
- return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: [meta.codingAgent, meta.backendApi].filter(Boolean).join(" \xB7 ") });
155
+ const agent = part.input?.codingAgent;
156
+ const backend = part.input?.backendApi;
157
+ if (agent || backend) {
158
+ return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: [agent, backend].filter(Boolean).join(" \xB7 ") });
159
+ }
160
+ if (isDone) {
161
+ const o = typeof part.output === "string" ? JSON.parse(part.output) : part.output;
162
+ const meta = Array.isArray(o) ? o.find((e) => e.type === "meta") : o;
163
+ if (meta?.codingAgent || meta?.backendApi) {
164
+ return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: [meta.codingAgent, meta.backendApi].filter(Boolean).join(" \xB7 ") });
165
+ }
159
166
  }
160
167
  } catch {
161
168
  }
@@ -154,17 +154,29 @@ function ToolCall({ part, className }) {
154
154
  <span className="flex flex-col min-w-0 flex-1">
155
155
  <span className="flex items-center gap-2">
156
156
  <span className="font-medium text-foreground">{displayName}</span>
157
- {isDone && (() => {
157
+ {(() => {
158
158
  try {
159
- const o = typeof part.output === 'string' ? JSON.parse(part.output) : part.output;
160
- const meta = Array.isArray(o) ? o.find(e => e.type === 'meta') : o;
161
- if (meta?.codingAgent || meta?.backendApi) {
159
+ // Read from input (available immediately) or output meta (historical chats)
160
+ const agent = part.input?.codingAgent;
161
+ const backend = part.input?.backendApi;
162
+ if (agent || backend) {
162
163
  return (
163
164
  <span className="text-xs text-muted-foreground">
164
- {[meta.codingAgent, meta.backendApi].filter(Boolean).join(' · ')}
165
+ {[agent, backend].filter(Boolean).join(' · ')}
165
166
  </span>
166
167
  );
167
168
  }
169
+ if (isDone) {
170
+ const o = typeof part.output === 'string' ? JSON.parse(part.output) : part.output;
171
+ const meta = Array.isArray(o) ? o.find(e => e.type === 'meta') : o;
172
+ if (meta?.codingAgent || meta?.backendApi) {
173
+ return (
174
+ <span className="text-xs text-muted-foreground">
175
+ {[meta.codingAgent, meta.backendApi].filter(Boolean).join(' · ')}
176
+ </span>
177
+ );
178
+ }
179
+ }
168
180
  } catch {}
169
181
  return null;
170
182
  })()}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thepopebot",
3
- "version": "1.2.75-beta.12",
3
+ "version": "1.2.75-beta.14",
4
4
  "type": "module",
5
5
  "description": "Create autonomous AI agents with a two-layer architecture: Next.js Event Handler + Docker Agent.",
6
6
  "bin": {
@@ -48,6 +48,9 @@ jobs:
48
48
  cd /project && npx --yes thepopebot@latest init --no-install
49
49
  fi
50
50
 
51
+ # Install the new version into node_modules so local CLI stays current
52
+ cd /project && npm install
53
+
51
54
  # Commit any template changes from init
52
55
  git -C /project add -A
53
56
  if ! git -C /project diff --cached --quiet; then
@@ -0,0 +1,31 @@
1
+ # Project Structure
2
+
3
+ This is a [thepopebot](https://github.com/stephengpope/thepopebot) project.
4
+
5
+ ## Directories
6
+
7
+ - **`agent-job/`** — Agent job configuration: system prompts (`SOUL.md`, `SYSTEM.md`), heartbeat prompt, and cron schedules (`CRONS.json`).
8
+ - **`agents/`** — Custom agent definitions. Each subdirectory defines an agent.
9
+ - **`event-handler/`** — Event handler configuration: chat system prompts, trigger definitions (`TRIGGERS.json`), cluster templates, and LiteLLM proxy config.
10
+ - **`skills/`** — Skill plugins. Activate by symlinking into `skills/active/`.
11
+ - **`data/`** — Runtime data (SQLite database, cluster state). Not checked into git.
12
+ - **`logs/`** — Agent job logs, organized by job ID. Not checked into git.
13
+
14
+ ## Files
15
+
16
+ - **`docker-compose.yml`** — Container definitions for the event handler and LiteLLM proxy. Managed — do not edit.
17
+ - **`docker-compose.custom.yml`** — Your Docker Compose overrides. Merged with the main compose file.
18
+ - **`.env`** — Environment variables (API keys, secrets). Never committed to git.
19
+
20
+ ## Managed Files
21
+
22
+ Some files are auto-synced by `npx thepopebot init` and will be overwritten on upgrade. Do not edit these:
23
+
24
+ - `.github/workflows/` — CI/CD workflows
25
+ - `docker-compose.yml`
26
+ - `.dockerignore`
27
+ - `.gitignore`
28
+ - `agent-job/CLAUDE.md`
29
+ - `agents/CLAUDE.md`
30
+ - `event-handler/CLAUDE.md`
31
+ - `skills/CLAUDE.md`
@@ -1,34 +1,57 @@
1
1
  # agent-job/ — Agent Job Configuration
2
2
 
3
- This directory contains configuration files for Docker agent jobs. These files are **not managed** your changes are preserved across upgrades.
3
+ This directory contains your agent job configuration files — system prompts, scheduling, and self-monitoring.
4
4
 
5
- ## File Reference
5
+ ## Files
6
6
 
7
- ### System Prompts
7
+ - **`SOUL.md`** — Agent personality, identity, and values. Included in every agent job system prompt.
8
+ - **`SYSTEM.md`** — Runtime environment documentation injected into the agent's context.
9
+ - **`HEARTBEAT.md`** — Prompt for the agent's periodic heartbeat cron job.
10
+ - **`CRONS.json`** — Scheduled job definitions, loaded at server startup.
8
11
 
9
- | File | Used By | Purpose |
10
- |------|---------|---------|
11
- | `SOUL.md` | Docker agent | Agent personality, identity, and values. Included in agent job system prompts. |
12
- | `SYSTEM.md` | Docker agent | Runtime environment documentation injected into the agent's context. |
13
- | `HEARTBEAT.md` | Heartbeat cron | Self-monitoring prompt for the agent's periodic heartbeat job. |
12
+ ## Editing CRONS.json
14
13
 
15
- ### Scheduling
14
+ `CRONS.json` is a JSON array of cron job objects. Each entry needs a `name`, `schedule` (cron expression), `type`, and `enabled` flag.
16
15
 
17
- | File | Purpose |
18
- |------|---------|
19
- | `CRONS.json` | Scheduled job definitions — loaded at server startup by `node-cron`. |
16
+ There are three action types:
20
17
 
21
- ## Template Variables
18
+ **`agent`** Launches a Docker agent container to execute an LLM task.
22
19
 
23
- Config markdown files support includes and built-in variables (processed by `render-md.js` at runtime):
20
+ ```json
21
+ {
22
+ "name": "heartbeat",
23
+ "schedule": "*/30 * * * *",
24
+ "type": "agent",
25
+ "job": "Read agent-job/HEARTBEAT.md and complete the tasks described there.",
26
+ "enabled": false
27
+ }
28
+ ```
24
29
 
25
- | Syntax | Description |
26
- |--------|-------------|
27
- | `{{ filepath.md }}` | Include another file (path relative to project root, recursive with circular detection) |
28
- | `{{datetime}}` | Current ISO timestamp |
29
- | `{{skills}}` | Dynamic bullet list of active skill descriptions from `skills/active/*/SKILL.md` frontmatter |
30
+ Optional: add `"llm_provider"` and `"llm_model"` to override the default LLM for that job.
30
31
 
31
- ## When Changes Take Effect
32
+ **`command`** Runs a shell command on the event handler (working directory: project root).
32
33
 
33
- - **Prompt files** (`.md`) — Changes take effect immediately on the next LLM call. No restart needed.
34
- - **CRONS.json** — Requires a server restart to reload schedules.
34
+ ```json
35
+ {
36
+ "name": "ping",
37
+ "schedule": "*/1 * * * *",
38
+ "type": "command",
39
+ "command": "echo \"pong!\"",
40
+ "enabled": true
41
+ }
42
+ ```
43
+
44
+ **`webhook`** — Makes an HTTP request. `POST` (default) sends `vars` as the body; `GET` skips the body.
45
+
46
+ ```json
47
+ {
48
+ "name": "health-check",
49
+ "schedule": "*/10 * * * *",
50
+ "type": "webhook",
51
+ "url": "https://example.com/health",
52
+ "method": "GET",
53
+ "enabled": false
54
+ }
55
+ ```
56
+
57
+ Optional webhook fields: `"method"` (default `POST`), `"headers"`, `"vars"`.
@@ -6,51 +6,11 @@
6
6
  "job": "Read the file at agent-job/HEARTBEAT.md and complete the tasks described there.",
7
7
  "enabled": false
8
8
  },
9
- {
10
- "name": "daily-check",
11
- "schedule": "0 9 * * *",
12
- "type": "agent",
13
- "job": "Check for dependency updates in package.json and report any outdated packages.",
14
- "enabled": false
15
- },
16
9
  {
17
10
  "name": "ping",
18
11
  "schedule": "*/1 * * * *",
19
12
  "type": "command",
20
13
  "command": "echo \"pong!\"",
21
14
  "enabled": true
22
- },
23
- {
24
- "name": "cleanup-logs",
25
- "schedule": "0 0 * * 0",
26
- "type": "command",
27
- "command": "ls -la logs/",
28
- "enabled": false
29
- },
30
- {
31
- "name": "ping-status",
32
- "schedule": "*/5 * * * *",
33
- "type": "webhook",
34
- "url": "https://example.com/status",
35
- "method": "POST",
36
- "vars": { "source": "heartbeat" },
37
- "enabled": false
38
- },
39
- {
40
- "name": "health-check",
41
- "schedule": "*/10 * * * *",
42
- "type": "webhook",
43
- "url": "https://example.com/health",
44
- "method": "GET",
45
- "enabled": false
46
- },
47
- {
48
- "name": "daily-check-openai",
49
- "schedule": "0 9 * * *",
50
- "type": "agent",
51
- "job": "Check for dependency updates in package.json and report any outdated packages.",
52
- "llm_provider": "openai",
53
- "llm_model": "gpt-4o",
54
- "enabled": false
55
15
  }
56
16
  ]
@@ -1,15 +1,15 @@
1
- # thepopebot Soul
1
+ # Agent Job Soul
2
2
 
3
3
  ## Identity
4
4
 
5
- You are a diligent and capable AI worker. You approach tasks with focus, patience, and craftsmanship.
5
+ You are a diligent and capable AI worker doing an job. You approach tasks with focus, patience, and craftsmanship.
6
6
 
7
7
  ## Personality Traits
8
8
 
9
9
  - **Methodical**: You work through problems systematically, step by step
10
10
  - **Reliable**: You follow through on commitments and complete what I start
11
11
  - **Curious**: You explore and learn from the codebase I work with
12
- - **Working Style**: You prefer to plan before acting
12
+ - **Working Style**: You plan before acting
13
13
 
14
14
  ## Values
15
15
 
@@ -1,30 +1,55 @@
1
- # thepopebot Agent Environment
1
+ # Agent Job Environment
2
2
 
3
- **This document describes what you are and your operating environment**
3
+ You are an autonomous AI agent running inside a Docker container on thepopebot.
4
4
 
5
- ---
5
+ ## Runtime Environment
6
6
 
7
- ## 1. What You Are
7
+ Your workspace is `/home/coding-agent/workspace` — a live git repository. Use `/tmp` for working files — downloads, intermediate data, scripts, generated files. `/tmp` is outside the repo and nothing there gets committed. If a tool downloads a file to `/tmp`, leave it there and reference it directly.
8
8
 
9
- You are **thepopebot**, an autonomous AI agent running inside a Docker container.
10
- - You have full access to the machine and anything it can do to get the job done.
9
+ Everything in the workspace is automatically committed and pushed when your job finishes. You do not control this. Be intentional about what you put here — **any file you create, move, or download into the workspace WILL be committed.**
11
10
 
12
- ---
11
+ Current datetime: {{datetime}}
13
12
 
14
- ## 2. Local Docker Environment Reference
13
+ ## Directory Layout
15
14
 
16
- ### WORKDIR`/job` is a git repo
15
+ - `agents/`Agent definitions. Each subdirectory defines an agent with its own prompts.
16
+ - `agent-job/` — Runtime config: system prompts (`SOUL.md`, `SYSTEM.md`), cron schedules (`CRONS.json`), heartbeat prompt.
17
+ - `event-handler/` — Event handler config. Do not edit — managed by the event handler.
18
+ - `skills/` — Skill plugins. Active skills are symlinked into `skills/active/`.
19
+ - `data/`, `logs/` — Runtime data and job logs.
17
20
 
18
- Your working directory is `/job`. **This is a live git repository.** When your job finishes, everything inside `/job` is automatically committed and pushed via `git add -A`. You do not control this — it happens after you exit.
21
+ ## What You Can Edit
19
22
 
20
- This means: **any file you create, copy, move, or download into `/job` or any subdirectory of `/job` WILL be committed to the repository.** There are no exceptions.
23
+ - `agent-job/CRONS.json` Add, remove, or change scheduled jobs
24
+ - `agents/` — Create or remove agent definitions
25
+ - `skills/active/` — Activate or deactivate skills via symlinks
26
+ - Agent prompt files (`.md`) in `agent-job/` and `agents/`
27
+ - Reports and output files
21
28
 
22
- ### All working files go in `/tmp`
29
+ ## What You Cannot Edit
23
30
 
24
- **NEVER save, copy, move, or download files into `/job`** unless the job specifically requires changing the repository (e.g. editing source code, updating config files).
31
+ - `event-handler/` — Chat prompts, triggers, clusters, LiteLLM config
32
+ - `docker-compose.yml`, `.dockerignore`, `.gitignore` — Managed infrastructure files
33
+ - `.env` — Environment secrets
25
34
 
26
- Use `/tmp` for everything else — downloads, generated files, images, videos, scripts, intermediate data, API responses, anything you create to get the job done. `/tmp` is outside the repo and nothing there gets committed.
35
+ ## Self-Modification
27
36
 
28
- If a skill or tool downloads a file to `/tmp`, **leave it there**. Do not copy or move it into `/job`. If you need to pass that file to another tool (e.g. uploading it somewhere), reference it directly from `/tmp`.
37
+ **Add an agent** Create `agents/<name>/` with a `prompts/` subfolder, add a cron entry in `agent-job/CRONS.json` pointing to the prompt file, update `agents/CLAUDE.md` to document it, update root `CLAUDE.md` to reflect the new agent.
29
38
 
30
- Current datetime: {{datetime}}
39
+ **Remove an agent** — Delete the `agents/<name>/` folder, remove its cron entries, update `agents/CLAUDE.md` and root `CLAUDE.md`.
40
+
41
+ **Change a schedule** — Edit `agent-job/CRONS.json` (cron expressions, enable/disable).
42
+
43
+ **Activate a skill** — Symlink from `skills/<name>/` into `skills/active/`, update root `CLAUDE.md`.
44
+
45
+ **Deactivate a skill** — Remove the symlink from `skills/active/`, update root `CLAUDE.md`.
46
+
47
+ **Keep CLAUDE.md files current** — When you change the structure of the instance (add/remove agents, change schedules, activate skills), update the root `CLAUDE.md` and any affected folder-level `CLAUDE.md` files so the next agent has an accurate picture.
48
+
49
+ ## Active Skills
50
+
51
+ {{skills}}
52
+
53
+ ## Orientation
54
+
55
+ Read the root `CLAUDE.md` for instance-specific context — what agents are deployed, what this instance is for. Read the `CLAUDE.md` in each folder you work in for local conventions.
File without changes
@@ -0,0 +1,5 @@
1
+ # agents/ — Custom Agent Definitions
2
+
3
+ This directory holds custom agent configurations. Each subdirectory defines an agent that can be referenced by agent jobs and cron tasks.
4
+
5
+ (No agents configured yet — add a subdirectory here to define one.)