letagents 0.12.28 → 0.12.30
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.
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { registerTools } from "./register-tools.js";
|
|
2
2
|
export const LETAGENTS_RUNTIME_CONTRACT_ARG = "--letagents-runtime-contract";
|
|
3
|
+
export const LETAGENTS_RUNTIME_READINESS_URI = "letagents://runtime/readiness";
|
|
3
4
|
/**
|
|
4
5
|
* Discover through the production registration path rather than maintaining a
|
|
5
6
|
* second capability list that can drift from the MCP server.
|
|
@@ -15,6 +16,16 @@ export function registeredToolNames(profile, supervisedProvider = null, apiUrl =
|
|
|
15
16
|
registerTools(recorder, profile, supervisedProvider, { apiUrl });
|
|
16
17
|
return [...names].sort();
|
|
17
18
|
}
|
|
19
|
+
/** Public capability metadata only; reading it grants no room or tool authority. */
|
|
20
|
+
export function registerRuntimeReadinessResource(server, profile, supervisedProvider, apiUrl = process.env.LETAGENTS_API_URL) {
|
|
21
|
+
const text = JSON.stringify({
|
|
22
|
+
format: 1, profile, provider: supervisedProvider,
|
|
23
|
+
tools: registeredToolNames(profile, supervisedProvider, apiUrl),
|
|
24
|
+
});
|
|
25
|
+
server.resource("runtime_readiness", LETAGENTS_RUNTIME_READINESS_URI, { mimeType: "application/json" }, async (uri) => ({
|
|
26
|
+
contents: [{ uri: uri.href, mimeType: "application/json", text }],
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
18
29
|
export function letAgentsRuntimeContract(apiUrl = process.env.LETAGENTS_API_URL) {
|
|
19
30
|
return {
|
|
20
31
|
format: 1,
|
|
@@ -170,7 +170,7 @@ export function registerBoardIntentTools(server) {
|
|
|
170
170
|
return taskToolError(String(error));
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
|
-
server.tool("register_task_claim_intent", "Register intent to claim an accepted task as the current worker.
|
|
173
|
+
server.tool("register_task_claim_intent", "Register intent to claim an accepted task as the current worker. Manager approval assigns the task and work lease immediately for authenticated workers; no second claim_task call is needed. Follow requires_follow_up only for legacy approvals.", {
|
|
174
174
|
task_id: z.string().describe("Task id to claim, e.g. task_12."),
|
|
175
175
|
...workerTaskIdentitySchema,
|
|
176
176
|
}, async ({ task_id, room_id, conversation_id: _conversation_id, agent_session_id }) => {
|
|
@@ -277,7 +277,7 @@ export function registerBoardIntentTools(server) {
|
|
|
277
277
|
return taskToolError(String(error));
|
|
278
278
|
}
|
|
279
279
|
});
|
|
280
|
-
server.tool("approve_board_intent", "Approve a pending board intent. For task_create intents this creates the task immediately and returns result.kind=\"task_created\"; do not call add_task afterward.
|
|
280
|
+
server.tool("approve_board_intent", "Approve a pending board intent. For task_create intents this creates the task immediately and returns result.kind=\"task_created\"; do not call add_task afterward. Authenticated-worker task_claim intents assign the task and work lease immediately with result.kind=\"task_claimed\" and requires_follow_up=false; do not call claim_task afterward. Other intents and legacy unverified claims require the exact follow-up with board_intent_id and the proposer's own worker session. The scoped approval token remains available for legacy callers; do not post it in room messages.", {
|
|
281
281
|
intent_id: z.string().describe("Board intent id to approve."),
|
|
282
282
|
reason: z.string().optional().describe("Short approval reason."),
|
|
283
283
|
...workerTaskIdentitySchema,
|
|
@@ -5,7 +5,7 @@ import { resolveCanonicalRoomId, resolveCanonicalTaskToolIdentity, taskActorPayl
|
|
|
5
5
|
import { jsonToolResponse, taskToolError } from "./response.js";
|
|
6
6
|
import { taskReviewIdentitySchema } from "./schemas.js";
|
|
7
7
|
export function registerTaskVerdictTools(server) {
|
|
8
|
-
server.tool("submit_review_verdict", "Submit a GitHub review verdict through the durable effect journal. Requires this exact worker session to hold an active review lease. Ambiguous
|
|
8
|
+
server.tool("submit_review_verdict", "Submit a GitHub review verdict through the durable effect journal. Requires this exact worker session to hold an active review lease. Success means GitHub confirmed publication; pending, failed, or uncertain effects keep their original idempotency key. Ambiguous outcomes are reconciled by correlation lookup and are never blindly retried.", {
|
|
9
9
|
task_id: z.string().describe("Task in review, e.g. 'task_1'."),
|
|
10
10
|
verdict: z.enum(["approve", "request_changes", "comment"]).describe("GitHub review verdict."),
|
|
11
11
|
body: z.string().max(65_536).optional().describe("Review explanation. Empty or junk blocking verdicts are quarantined."),
|
|
@@ -34,13 +34,26 @@ export function registerTaskVerdictTools(server) {
|
|
|
34
34
|
}),
|
|
35
35
|
},
|
|
36
36
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const published = result.effect.state === "succeeded";
|
|
38
|
+
const publicationStatus = published ? `published ${verdict} verdict for ${task_id}`
|
|
39
|
+
: result.effect.quarantined_at ? `review publication blocked for ${task_id}`
|
|
40
|
+
: result.effect.state === "failed" ? `review publication failed for ${task_id}`
|
|
41
|
+
: result.effect.state === "pending" ? `review publication pending for ${task_id}`
|
|
42
|
+
: `review publication outcome unknown for ${task_id}`;
|
|
43
|
+
// Presence is a secondary notification. Its failure cannot erase an
|
|
44
|
+
// exact journal receipt or turn a known publication into a new retry.
|
|
45
|
+
try {
|
|
46
|
+
await syncRoomPresence(targetRoomId, identity, {
|
|
47
|
+
status: "reviewing",
|
|
48
|
+
status_text: publicationStatus,
|
|
49
|
+
}, agentSession);
|
|
50
|
+
}
|
|
51
|
+
catch { /* Return the durable effect even when presence is unavailable. */ }
|
|
41
52
|
return jsonToolResponse({
|
|
42
|
-
success: true,
|
|
43
53
|
...result,
|
|
54
|
+
success: published,
|
|
55
|
+
message: published ? "The review was published on GitHub."
|
|
56
|
+
: `${publicationStatus}. The returned effect is the publication record; do not submit a new idempotency key to retry it.`,
|
|
44
57
|
agent_identity: toPublicAgentIdentity(identity),
|
|
45
58
|
}, 2);
|
|
46
59
|
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -7,20 +7,22 @@ import { attachMcpServer, autoJoinFromContext, shutdownRuntime } from "./server/
|
|
|
7
7
|
import { requireValidWorkerBearerRuntime } from "./server/runtime/worker-bearer.js";
|
|
8
8
|
import { executionProfile } from "./server/runtime/execution-profile.js";
|
|
9
9
|
import { WORKSPACE_CAPTURE_INSTRUCTIONS } from "./server/tools/workspace.js";
|
|
10
|
-
import { LETAGENTS_RUNTIME_CONTRACT_ARG, letAgentsRuntimeContract, } from "./server/runtime-contract.js";
|
|
10
|
+
import { LETAGENTS_RUNTIME_CONTRACT_ARG, letAgentsRuntimeContract, registerRuntimeReadinessResource, } from "./server/runtime-contract.js";
|
|
11
11
|
async function main() {
|
|
12
12
|
if (process.argv.slice(2).includes(LETAGENTS_RUNTIME_CONTRACT_ARG)) {
|
|
13
13
|
process.stdout.write(`${JSON.stringify(letAgentsRuntimeContract())}\n`);
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
const profile = executionProfile();
|
|
17
|
+
const supervisedProvider = process.env.LETAGENTS_SUPERVISOR_PROVIDER?.trim() || null;
|
|
17
18
|
const server = new McpServer({
|
|
18
19
|
name: "letagents",
|
|
19
20
|
version: "0.2.0",
|
|
20
21
|
}, { instructions: profile === "autonomous_mcp_worker" || profile === "interactive_desktop" ? WORKSPACE_CAPTURE_INSTRUCTIONS : undefined });
|
|
21
22
|
attachMcpServer(server);
|
|
22
23
|
registerRoomResources(server);
|
|
23
|
-
registerTools(server, profile);
|
|
24
|
+
registerTools(server, profile, supervisedProvider);
|
|
25
|
+
registerRuntimeReadinessResource(server, profile, supervisedProvider);
|
|
24
26
|
requireValidWorkerBearerRuntime();
|
|
25
27
|
const transport = new StdioServerTransport();
|
|
26
28
|
await server.connect(transport);
|