Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ export class Service {
properties: {
decision: { type: "string", enum: ["hold", "wake", "open_ask", "close_ask", "reopen_ask"] },
why: { type: "string" },
ref: { type: "string" },
ref: { type: "string", pattern: "^r\\d+$" },
itemId: { type: "string" },
},
},
Expand All @@ -436,7 +436,7 @@ export class Service {
const a = args as { decision: string; why: string; ref?: string; itemId?: string };
const target = a.ref ? refs.get(a.ref) : undefined;
if (a.ref && !target) {
return { success: false, output: "no such ref in this batch — use an [rN] tag from the lines you were shown" };
return { success: false, output: `"${a.ref}" is not a ref — copy the [rN] tag (like r3) from the start of the line you are judging; timestamps and channel ids are labels, not addresses` };
}
const venueId = target?.venueId;
// hold/wake judge the conversation the message LIVES in (a top-level line is surface
Expand Down
10 changes: 5 additions & 5 deletions src/turn-runner/toolset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,19 +295,19 @@ function replyTool(ctx: ToolsetContext): ToolFactory {
spec: {
name: "reply",
description:
"Post a message into a conversation. ref is the [rN] tag from the line you're answering (a message ref replies in its thread; a conversation ref posts there). Refs come only from what you can see — there is no other way to address a room.",
"Post a message into a conversation. ref is the [rN] tag copied from the start of the line you're answering — always the r-number (like r3), never a timestamp, channel id, or thread id (those are labels, not addresses). A message ref replies in its thread; a conversation ref posts there. Refs come only from what you can see — there is no other way to address a room.",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["text", "ref"],
properties: { text: { type: "string" }, ref: { type: "string" } },
properties: { text: { type: "string" }, ref: { type: "string", pattern: "^r\\d+$" } },
},
},
impl: async (args) => {
const a = args as { text: string; ref?: string };
const target = a.ref ? ctx.refs?.get(a.ref) : undefined;
if (!target) {
return { success: false, output: "no such ref — pass the [rN] tag from a line you were shown (message tags answer in that thread; the conversation tag posts there)" };
return { success: false, output: `"${a.ref ?? ""}" is not a ref — copy the [rN] tag (like r3) from the start of a line you were shown; timestamps and channel ids are labels, not addresses` };
}
const key = conversationOf(target);
const anchor: Anchor = { venueId: key.venueId, threadRootId: key.threadRootId };
Expand Down Expand Up @@ -371,7 +371,7 @@ function reactTool(ctx: ToolsetContext): ToolFactory {
type: "object",
additionalProperties: false,
required: ["emoji", "ref"],
properties: { emoji: { type: "string" }, ref: { type: "string" } },
properties: { emoji: { type: "string" }, ref: { type: "string", pattern: "^r\\d+$" } },
},
},
impl: async (args) => {
Expand Down Expand Up @@ -803,7 +803,7 @@ function stepBackTool(ctx: ToolsetContext): ToolFactory {
type: "object",
additionalProperties: false,
required: ["why", "ref"],
properties: { why: { type: "string" }, ref: { type: "string" } },
properties: { why: { type: "string" }, ref: { type: "string", pattern: "^r\\d+$" } },
},
},
impl: async (args) => {
Expand Down
2 changes: 1 addition & 1 deletion test/resident.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ describe("resident delivery", () => {
await service.start();
await service.idle(); // flushes the boot wake carrying both conversations

expect(rejected[0]).toContain("no such ref");
expect(rejected[0]).toContain("is not a ref");
expect(adapter.posts).toHaveLength(1);
expect(adapter.posts[0]!.venueId).toBe("C1"); // where the answer belongs...
expect(adapter.posts[0]!.threadRootTs).toBe("1.0"); // ...in ITS thread, not the batch's last
Expand Down
2 changes: 1 addition & 1 deletion test/toolset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ describe("reply posting-scope rule (SPEC §11) — addressing as refs", () => {
expect(JSON.stringify(replyTool.spec.inputSchema)).not.toContain("venueId");
const bare = await replyTool.run({ text: "hi" });
expect(bare.success).toBe(false);
expect(bare.output).toContain("no such ref");
expect(bare.output).toContain("is not a ref");
const invented = await replyTool.run({ text: "hi", ref: "r99" });
expect(invented.success).toBe(false);
const smuggled = await replyTool.run({ text: "hi", ref: "r1", venueId: "C1", threadRootId: "9.9" });
Expand Down
Loading