eve-hub 0.16.1 → 0.16.3
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.
- package/CHANGELOG.md +6 -0
- package/bubbles.d.mts +2 -0
- package/bubbles.mjs +23 -0
- package/package.json +1 -1
- package/templates/reaching-others.md +2 -1
- package/templates/writing.md +2 -1
- package/tools/post_message.js +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# eve-hub
|
|
2
2
|
|
|
3
|
+
## 0.16.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- A status post is a phase marker of at most 8 words with no @-mention; the brief, question or handoff goes in its own post. The shared instructions say so, and the hub refuses a status post that carries more.
|
|
8
|
+
|
|
3
9
|
## 0.16.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/bubbles.d.mts
ADDED
package/bubbles.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// The bubble rule: a post's text splits into bubbles at each top-level
|
|
2
|
+
// thematic break, by CommonMark's rules, as the app splits it
|
|
3
|
+
// (MarkdownCards.swift, `case .rule`). A `---` in code, an HTML block, a list
|
|
4
|
+
// or a quote is no break. Bots write the break as BUBBLE_BREAK. The cap
|
|
5
|
+
// (post_message) and what an unnamed reader is shown (delivery-context) both
|
|
6
|
+
// cut here.
|
|
7
|
+
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
8
|
+
|
|
9
|
+
export const BUBBLE_BREAK = "\n\n---\n\n";
|
|
10
|
+
|
|
11
|
+
export function bubbles(text) {
|
|
12
|
+
const s = String(text ?? "");
|
|
13
|
+
const out = [];
|
|
14
|
+
let from = 0;
|
|
15
|
+
for (const node of fromMarkdown(s).children) {
|
|
16
|
+
if (node.type !== "thematicBreak") continue;
|
|
17
|
+
out.push(s.slice(from, node.position.start.offset));
|
|
18
|
+
from = node.position.end.offset;
|
|
19
|
+
}
|
|
20
|
+
out.push(s.slice(from));
|
|
21
|
+
const drawn = out.map((b) => b.replace(/^\n+|\n+$/g, "")).filter((b) => b.trim());
|
|
22
|
+
return drawn.length ? drawn : [s];
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve-hub",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Bot-side code shared by every hub agent: registry tools, the roster hook, the eve channel, the host sandbox and browser, and model helpers.",
|
|
6
6
|
"type": "module",
|
|
@@ -16,4 +16,5 @@
|
|
|
16
16
|
- `policy: "steer"` adds your input to the turn it's running; `"abort"` stops it and your text starts its next turn.
|
|
17
17
|
- Use them only to correct work already under way; otherwise queue.
|
|
18
18
|
- **Phase**
|
|
19
|
-
- When the thread's phase changes (planning, working, reviewing, done),
|
|
19
|
+
- When the thread's phase changes (planning, working, reviewing, done), add a status post: at most 8 plain words, no @-mention.
|
|
20
|
+
- The brief, question or handoff is its own post, without `status`: the app draws a status post as a grey phase row, and the hub refuses one that carries more.
|
package/templates/writing.md
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
- How: a `flow`, `sequence`, `chart` or `ask` form sent with `post_message`; load the `forms` skill for the shapes, tables and syntax.
|
|
8
8
|
- Never draw with characters: no arrows, boxes, numbered timelines or tables in a code fence.
|
|
9
9
|
- **Disclose one step at a time**
|
|
10
|
-
- A post is at most 2 sentences (the point or the question; the inbox shows only its first line), then at most 3 bullets or one small table: what the reader needs to act, and nothing more.
|
|
10
|
+
- A post is at most 2 sentences (the point or the question; the inbox shows only its first line), then at most 3 bullets or one small table: what the reader needs to act, and nothing more.
|
|
11
|
+
- Supporting detail for the same message can follow a `---` line, with a blank line on each side; it becomes a second bubble, and each bubble holds up to 700 characters. The first bubble must stand alone: a bot the post doesn't name sees only it. A new update, a separate ask or handoff, or anything that needs its own recipient or status is another `post_message`. Most posts are one bubble.
|
|
11
12
|
- Depth (evidence, analysis, options, a long table) goes in a doc: write a markdown file in your sandbox and link it in the post, `[the analysis](/workspace/notes/analysis.md)`; `post_message` uploads it and the link opens it beside the thread, already styled. Never paste it. Write HTML only for a layout markdown can't hold, following the `vercel-design` skill when you have it.
|
|
12
13
|
- Images go in `post_message`'s `images` (sandbox paths), never in the text.
|
|
13
14
|
- A file reaches the human only as a markdown link in a post or through `show`, which upload it. A raw sandbox path in text is a file they can't open.
|
package/tools/post_message.js
CHANGED
|
@@ -2,6 +2,7 @@ import { defineTool } from "eve/tools";
|
|
|
2
2
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { documentUrl, hostedHub, isSandboxPath, uploadBytes, uploadFile } from "../hub-upload.js";
|
|
5
|
+
import { bubbles } from "../bubbles.mjs";
|
|
5
6
|
import { registryFetch } from "../registry-fetch.mjs";
|
|
6
7
|
// Posts as you into a thread or DM, from whichever session you're in. With no
|
|
7
8
|
// target it posts into the thread you're in, as part of the running turn: once
|
|
@@ -11,7 +12,7 @@ import { registryFetch } from "../registry-fetch.mjs";
|
|
|
11
12
|
// thread, if any, isn't woken; it sees the message as yours the next time it's
|
|
12
13
|
// addressed.
|
|
13
14
|
//
|
|
14
|
-
//
|
|
15
|
+
// Each bubble of the text is capped (MAX_CHARS, link targets excluded): depth goes in a
|
|
15
16
|
// document the post links by its sandbox path, which is uploaded and the link
|
|
16
17
|
// rewritten to where the hub serves it (hub-upload.ts). Images go in `images`
|
|
17
18
|
// and ride the post.
|
|
@@ -51,8 +52,9 @@ export const postLength = (text) => destinations(text).reduce((n, d) => n - (d.t
|
|
|
51
52
|
export function textError(text) {
|
|
52
53
|
if (destinations(text).some((d) => d.kind === "image"))
|
|
53
54
|
return "Images don't go in the text: pass the file's sandbox path in `images` and it shows inline";
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
const over = bubbles(text).findIndex((b) => postLength(b) > MAX_CHARS);
|
|
56
|
+
if (over >= 0)
|
|
57
|
+
return `Too long: bubble ${over + 1} is over ${MAX_CHARS} characters; move the detail into a doc and link it`;
|
|
56
58
|
return null;
|
|
57
59
|
}
|
|
58
60
|
const PATH_AND_FRAGMENT = /^([^?#]*)(?:\?[^#]*)?(#.*)?$/;
|
|
@@ -93,11 +95,11 @@ async function screenshot(sessionId) {
|
|
|
93
95
|
return browser.screenshot();
|
|
94
96
|
}
|
|
95
97
|
export default defineTool({
|
|
96
|
-
description: "Post a message as you. Leave out threadId and agent to post into the thread you're in, while you work: posting doesn't end your turn, and once your turn has posted into this thread, its end-of-turn text isn't posted, so put your result in a post. Or post into another workspace thread or a bot's DM.
|
|
98
|
+
description: "Post a message as you. Leave out threadId and agent to post into the thread you're in, while you work: posting doesn't end your turn, and once your turn has posted into this thread, its end-of-turn text isn't posted, so put your result in a post. Or post into another workspace thread or a bot's DM. Each bubble is at most 700 characters (link targets don't count); a `---` line with blank lines around it starts a new bubble. Lead with the point in 2 sentences, then at most 3 bullets or one small table. Depth goes in a document: write it to a file and link it in the text by its sandbox path, `[the plan](/workspace/plan.md)`; the file is uploaded and the link opens it beside the thread. Images go in `images` (sandbox paths; `screenshot` for your browser's page on a local hub) and show inline; never write `![]()`. @-mentions wake bots the same way your replies do (at most one, never yourself); `@all` wakes every participant; each bot's gate decides whether it replies. Posting into a bot's DM wakes that bot. Archived threads are refused. `policy` says how a post reaches the one bot it @-mentions: queue (default) runs as its next turn, or starts one now if it is idle; steer lands in its RUNNING turn at the next step boundary and the bot folds it in without a restart, to correct course mid-turn; abort stops its turn in that thread (running commands are killed, the process keeps running) and the text starts its fresh turn, \"stop, do this instead\". Steer and abort need exactly one @-mention, not `@all`, and cut into work already under way: use them only to change what a running turn is doing. A status post sets the thread's phase: planning, working, reviewing or done; allowed moves are start → planning or working, planning → working, working → reviewing, reviewing → working (fix first), planning (rethink) or done. Any other move is refused with the allowed next phases. The text is a phase marker, not a report: at most 8 plain words on what is happening now (\"Building the input-count fix\"), with no bot or role names, no restating the phase, no parentheticals. Test results, branch names and caveats go in a separate message. The PR URL and sha go in metadata, never in the text.",
|
|
97
99
|
inputSchema: z.object({
|
|
98
100
|
threadId: z.string().optional().describe("Another thread's id, e.g. thr_0002, or a DM id, dm-<bot>. Omit it to post into the thread you're in."),
|
|
99
101
|
agent: z.string().optional().describe("Post into this bot's DM instead of a thread."),
|
|
100
|
-
text: z.string().describe("The message, at most 700 characters (link targets don't count). A markdown link to a sandbox path uploads that document. @-mention the one bot who should act. On a status post: at most 8 plain words on what is happening now."),
|
|
102
|
+
text: z.string().describe("The message, at most 700 characters per bubble (link targets don't count); a `---` line with blank lines around it starts a new bubble. A markdown link to a sandbox path uploads that document. @-mention the one bot who should act. On a status post: at most 8 plain words on what is happening now."),
|
|
101
103
|
images: z.array(z.string()).optional().describe("Images to show inline on this post: sandbox paths (PNG, JPEG, GIF or WebP, up to 3 MB each), or `screenshot` for your browser's current page (local hub only)."),
|
|
102
104
|
policy: z.enum(["queue", "steer", "abort"]).optional().describe("How the post reaches the one bot it @-mentions: queue (default), steer into its running turn, or abort its turn and start a fresh one on this text."),
|
|
103
105
|
status: z.enum(["planning", "working", "reviewing", "done"]).optional().describe("The thread's phase after this post. Makes it a status post."),
|