@sjawhar/pi-legion-envoy 5.16.8 → 5.16.10
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/dist/envoy.js +62 -9
- package/dist/legion.js +1120 -154
- package/dist/skills/dispatch/SKILL.md +14 -6
- package/dist/skills/legion-worker/SKILL.md +35 -12
- package/package.json +1 -1
package/dist/envoy.js
CHANGED
|
@@ -30028,6 +30028,16 @@ var messageValidation = {
|
|
|
30028
30028
|
},
|
|
30029
30029
|
message: "issue is required unless in_reply_to names a message delivered to this session, which is the one message with no issue."
|
|
30030
30030
|
};
|
|
30031
|
+
var readOwner = documentOwnerValidation(true);
|
|
30032
|
+
var readValidation = {
|
|
30033
|
+
check: (value) => {
|
|
30034
|
+
const input = value;
|
|
30035
|
+
if (typeof input.message !== "string")
|
|
30036
|
+
return readOwner.check(value);
|
|
30037
|
+
return input.issue === undefined && input.project === undefined && input.artifact === undefined && input.ref === undefined;
|
|
30038
|
+
},
|
|
30039
|
+
message: `${readOwner.message} message stands alone: it names the conversation, so name no issue, project, artifact, or ref with it.`
|
|
30040
|
+
};
|
|
30031
30041
|
var ISSUE_COMPONENTS_MODES = ["inherit", "explicit", "none"];
|
|
30032
30042
|
function componentsArgument(z2) {
|
|
30033
30043
|
return z2.object({
|
|
@@ -30255,7 +30265,7 @@ var dispatchToolSpecs = [
|
|
|
30255
30265
|
{
|
|
30256
30266
|
name: "dispatch_message",
|
|
30257
30267
|
example: { issue: "DSP-1", body: "Implementation started." },
|
|
30258
|
-
description: "Post a note humans must read now: a reply to a human's message or a deliverable that landed. A blocker only a human can " + "clear is an ask (dispatch_ask), so it lands in their inbox. Never progress or status updates - Dispatch is a high-signal " + "record, not a log. Not a decision (dispatch_ask) or document feedback (dispatch_comment). To answer a human's direct message to this session - " + "one sent from the Agents page, which names no issue - pass that message's bare id as in_reply_to and no issue; " + "the reply lands in that conversation
|
|
30268
|
+
description: "Post a note humans must read now: a reply to a human's message or a deliverable that landed. A blocker only a human can " + "clear is an ask (dispatch_ask), so it lands in their inbox. Never progress or status updates - Dispatch is a high-signal " + "record, not a log. Not a decision (dispatch_ask) or document feedback (dispatch_comment). To answer a human's direct message to this session - " + "one sent from the Agents page, which names no issue - pass that message's bare id as in_reply_to and no issue; " + "the reply lands in that conversation. Another call with the same in_reply_to and new text posts a follow-up, " + "threaded under this session's first reply; the same text again posts nothing. dispatch_read({message}) reads " + "that conversation back. Every other message names its issue. " + `Body is at most 2,000 characters. ${ISSUE_REFERENCE}`,
|
|
30259
30269
|
arguments: (z2) => ({
|
|
30260
30270
|
issue: z2.string().describe(`${ISSUE_REFERENCE} Omit it only when in_reply_to answers a human's direct message to this session.`).optional(),
|
|
30261
30271
|
body: z2.string({ max: 2000 }).describe("Update text, at most 2,000 characters."),
|
|
@@ -30349,14 +30359,15 @@ var dispatchToolSpecs = [
|
|
|
30349
30359
|
{
|
|
30350
30360
|
name: "dispatch_read",
|
|
30351
30361
|
example: { issue: "DSP-1" },
|
|
30352
|
-
description: "Read an issue or project-document summary, targeted ask, or targeted comment reply chain. Do not use it for document
|
|
30362
|
+
description: "Read an issue or project-document summary, targeted ask, or targeted comment reply chain, or the conversation " + "a message belongs to. Do not use it for document contents; use dispatch_doc_read instead. Supply ref, issue, " + "or project plus artifact; or message alone, which reads a human's direct message to this session and every " + "reply to it (they belong to no issue). " + "Every read ends with `Referenced by:` (what cites or hangs off this node, each with its dispatch:// address, " + "an excerpt, and when) and `Links:` (what it cites), so tracing provenance is one call. " + OWNER_REFERENCE,
|
|
30353
30363
|
arguments: (z2) => ({
|
|
30354
30364
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
30355
30365
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
30356
30366
|
artifact: z2.string().describe("Project document artifact id, slug, or filename.").optional(),
|
|
30357
|
-
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional()
|
|
30367
|
+
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
30368
|
+
message: z2.string().describe("A message id (uuid): reads the conversation it belongs to, the root message and every " + "reply. Name nothing else with it.").optional()
|
|
30358
30369
|
}),
|
|
30359
|
-
validation:
|
|
30370
|
+
validation: readValidation
|
|
30360
30371
|
},
|
|
30361
30372
|
{
|
|
30362
30373
|
name: "dispatch_search",
|
|
@@ -32443,8 +32454,8 @@ class DispatchClient {
|
|
|
32443
32454
|
async message(issue2, input) {
|
|
32444
32455
|
return this.#json("POST", ["api", "v1", "issues", await this.#resolveIssue(issue2), "messages"], input);
|
|
32445
32456
|
}
|
|
32446
|
-
async messageReply(id, input) {
|
|
32447
|
-
return this.#json("POST", ["api", "v1", "messages", id, "reply"], input);
|
|
32457
|
+
async messageReply(id, input, options = {}) {
|
|
32458
|
+
return this.#json("POST", ["api", "v1", "messages", id, "reply"], input, options.followUp === true ? { follow_up: "true" } : undefined);
|
|
32448
32459
|
}
|
|
32449
32460
|
async getMessage(issue2, id) {
|
|
32450
32461
|
return this.#json("GET", [
|
|
@@ -32456,6 +32467,9 @@ class DispatchClient {
|
|
|
32456
32467
|
id
|
|
32457
32468
|
]);
|
|
32458
32469
|
}
|
|
32470
|
+
async getMessageThread(id, session) {
|
|
32471
|
+
return this.#json("GET", ["api", "v1", "messages", id], undefined, { session });
|
|
32472
|
+
}
|
|
32459
32473
|
async artifact(issue2, input) {
|
|
32460
32474
|
const artifactPath = ["api", "v1", "issues", await this.#resolveIssue(issue2), "artifacts"];
|
|
32461
32475
|
if ("content" in input)
|
|
@@ -33107,6 +33121,13 @@ function argumentProblems(tool, args) {
|
|
|
33107
33121
|
}
|
|
33108
33122
|
break;
|
|
33109
33123
|
}
|
|
33124
|
+
case "dispatch_read": {
|
|
33125
|
+
const message = optionalString(args, "message");
|
|
33126
|
+
if (message !== undefined && messageIdOf(message) === undefined) {
|
|
33127
|
+
problems.push("message must be a full message id (uuid) or a dispatch://KEY/message/<id> reference");
|
|
33128
|
+
}
|
|
33129
|
+
break;
|
|
33130
|
+
}
|
|
33110
33131
|
}
|
|
33111
33132
|
return problems;
|
|
33112
33133
|
}
|
|
@@ -33244,6 +33265,9 @@ async function resolveOwnerArguments(tool, input, cwd, env, exec, serverUrl, pro
|
|
|
33244
33265
|
if (tool === "dispatch_message" && typeof replyTarget === "string" && !replyTarget.startsWith("dispatch://")) {
|
|
33245
33266
|
return { args, ref, owner: null };
|
|
33246
33267
|
}
|
|
33268
|
+
if (tool === "dispatch_read" && typeof args.message === "string") {
|
|
33269
|
+
return { args, ref, owner: null };
|
|
33270
|
+
}
|
|
33247
33271
|
const legionIssue = env.LEGION_ISSUE;
|
|
33248
33272
|
if (!legionIssue) {
|
|
33249
33273
|
problems.push(ownerRequiredProblem);
|
|
@@ -34166,16 +34190,30 @@ ${followsAsk(askOwner)}`,
|
|
|
34166
34190
|
const inReplyTo = messageInReplyTo(args);
|
|
34167
34191
|
const body = stringArg(args, "body");
|
|
34168
34192
|
if (owner === null && inReplyTo !== undefined) {
|
|
34169
|
-
const reply = await client.messageReply(inReplyTo, { body, attempt: 1, actor });
|
|
34193
|
+
const reply = await client.messageReply(inReplyTo, { body, attempt: 1, actor }, { followUp: true });
|
|
34194
|
+
if (reply.duplicate === true && reply.body === body) {
|
|
34195
|
+
return {
|
|
34196
|
+
text: `Dispatch already has this exact text in the conversation (message ${reply.id}); ` + "nothing new was posted. Send different text if you have more to say.",
|
|
34197
|
+
details: { message: reply.id, in_reply_to: inReplyTo, posted: false, duplicate: true }
|
|
34198
|
+
};
|
|
34199
|
+
}
|
|
34170
34200
|
if (reply.body !== body) {
|
|
34171
34201
|
return {
|
|
34172
34202
|
text: `Message ${inReplyTo} was already answered by message ${reply.id}; Dispatch kept ` + "that reply and posted nothing. Wait for their next message rather than answering " + "this one again.",
|
|
34173
34203
|
details: { message: reply.id, in_reply_to: inReplyTo, posted: false }
|
|
34174
34204
|
};
|
|
34175
34205
|
}
|
|
34206
|
+
const readBack = `dispatch_read({message: "${inReplyTo}"}) reads the conversation back.`;
|
|
34207
|
+
const parent = reply.in_reply_to ?? undefined;
|
|
34208
|
+
const follows = parent === inReplyTo ? undefined : parent;
|
|
34176
34209
|
return {
|
|
34177
|
-
text: `Replied to message ${inReplyTo} with message ${reply.id}`,
|
|
34178
|
-
details: {
|
|
34210
|
+
text: follows === undefined ? `Replied to message ${inReplyTo} with message ${reply.id}. ${readBack}` : `Replied to message ${inReplyTo} with message ${reply.id}, a follow-up threaded ` + `under your reply ${follows}. ${readBack}`,
|
|
34211
|
+
details: {
|
|
34212
|
+
message: reply.id,
|
|
34213
|
+
in_reply_to: inReplyTo,
|
|
34214
|
+
posted: true,
|
|
34215
|
+
...follows === undefined ? {} : { follows }
|
|
34216
|
+
}
|
|
34179
34217
|
};
|
|
34180
34218
|
}
|
|
34181
34219
|
const issueKey = issue2();
|
|
@@ -34347,6 +34385,21 @@ ${trailer.join(`
|
|
|
34347
34385
|
};
|
|
34348
34386
|
}
|
|
34349
34387
|
case "dispatch_read": {
|
|
34388
|
+
const message = optionalString(args, "message");
|
|
34389
|
+
if (message !== undefined) {
|
|
34390
|
+
const sessionId = input.sessionId?.trim();
|
|
34391
|
+
if (!sessionId)
|
|
34392
|
+
throw new Error("host session id is required for dispatch_read({message})");
|
|
34393
|
+
const thread = await client.getMessageThread(messageIdOf(message), sessionId);
|
|
34394
|
+
const issueKey2 = thread.message.issue_key;
|
|
34395
|
+
return {
|
|
34396
|
+
text: messageSummary(thread, issueKey2 === null ? [] : await graphSections(client, dispatchChildRef(dispatchIssueRef(issueKey2), "message", thread.message.id))),
|
|
34397
|
+
details: {
|
|
34398
|
+
message: thread.message.id,
|
|
34399
|
+
...issueKey2 === null ? {} : { issue: issueKey2 }
|
|
34400
|
+
}
|
|
34401
|
+
};
|
|
34402
|
+
}
|
|
34350
34403
|
if (ownerArguments.ref?.kind === "ask") {
|
|
34351
34404
|
const ref = ownerArguments.ref;
|
|
34352
34405
|
const id = await resolveIdPrefix(input.tool, "ask", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks((await resolveDocument(ref.owner, ref.artifact)).artifact.id, "all"));
|