@kynver-app/mcp-agent-os 0.3.9 → 0.3.13
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/server.js +3 -0
- package/dist/tools/graph.d.ts +22 -0
- package/dist/tools/graph.js +91 -0
- package/dist/tools/plans.js +5 -1
- package/dist/tools/tasks.js +35 -5
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -13,6 +13,7 @@ import { registerPlanTools } from "./tools/plans.js";
|
|
|
13
13
|
import { registerPlanProgressTools } from "./tools/plan-progress.js";
|
|
14
14
|
import { registerTaskTools } from "./tools/tasks.js";
|
|
15
15
|
import { registerActionRequiredTools } from "./tools/action-required.js";
|
|
16
|
+
import { registerGraphTools } from "./tools/graph.js";
|
|
16
17
|
function jsonResult(data) {
|
|
17
18
|
return {
|
|
18
19
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
@@ -614,5 +615,7 @@ export function createAgentOsServer() {
|
|
|
614
615
|
registerPlanProgressTools({ register, resolveToolSlug, jsonResult, compact });
|
|
615
616
|
// Action Required inbox: agent_os_ask_human + agent_os_await_action (slice 1).
|
|
616
617
|
registerActionRequiredTools({ register, jsonResult, compact });
|
|
618
|
+
// Operational graph insights — Agent SEE (agent_os_graph_query).
|
|
619
|
+
registerGraphTools({ register, resolveToolSlug, jsonResult });
|
|
617
620
|
return server;
|
|
618
621
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operational-graph MCP tools — "Agent SEE" (graph M6).
|
|
3
|
+
*
|
|
4
|
+
* agent_os_graph_query proxies to GET `/api/agent-os/{slug}/graph/query`, which
|
|
5
|
+
* returns server-computed insights (bottlenecks, per-owner load, orphans) over
|
|
6
|
+
* the operational graph. Read-only; the Kynver route enforces session +
|
|
7
|
+
* workspace scope. Kept in its own module so server.ts stays slim.
|
|
8
|
+
*/
|
|
9
|
+
type ToolResult = {
|
|
10
|
+
content: {
|
|
11
|
+
type: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
}[];
|
|
14
|
+
structuredContent?: unknown;
|
|
15
|
+
};
|
|
16
|
+
export interface GraphToolDeps {
|
|
17
|
+
register: (name: string, description: string, inputSchema: Record<string, unknown>, cb: (args: any) => any) => void;
|
|
18
|
+
resolveToolSlug: (explicitSlug?: string) => Promise<string>;
|
|
19
|
+
jsonResult: (data: unknown) => ToolResult;
|
|
20
|
+
}
|
|
21
|
+
export declare function registerGraphTools({ register, resolveToolSlug, jsonResult }: GraphToolDeps): void;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operational-graph MCP tools — "Agent SEE" (graph M6).
|
|
3
|
+
*
|
|
4
|
+
* agent_os_graph_query proxies to GET `/api/agent-os/{slug}/graph/query`, which
|
|
5
|
+
* returns server-computed insights (bottlenecks, per-owner load, orphans) over
|
|
6
|
+
* the operational graph. Read-only; the Kynver route enforces session +
|
|
7
|
+
* workspace scope. Kept in its own module so server.ts stays slim.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { get, post } from "../lib/kynver-client.js";
|
|
11
|
+
export function registerGraphTools({ register, resolveToolSlug, jsonResult }) {
|
|
12
|
+
register("agent_os_graph_query", [
|
|
13
|
+
"Read the operational graph's computed insights for the AgentOS:",
|
|
14
|
+
"top bottlenecks (highest downstream impact among still-active or blocked work),",
|
|
15
|
+
"per-owner load (who is carrying work and who is blocked), and orphaned tasks.",
|
|
16
|
+
"Use this to answer questions like 'what is my biggest bottleneck',",
|
|
17
|
+
"'what is blocking project X', 'what is <persona> working on', or 'what is unassigned'.",
|
|
18
|
+
"Read-only — modifies nothing. Returns { available, generatedAt, stats, insights }.",
|
|
19
|
+
].join(" "), {
|
|
20
|
+
slug: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("AgentOS slug. Defaults to the configured env/primary AgentOS."),
|
|
24
|
+
bottlenecks: z
|
|
25
|
+
.number()
|
|
26
|
+
.int()
|
|
27
|
+
.min(1)
|
|
28
|
+
.max(50)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Max bottleneck rows to return (default 10)."),
|
|
31
|
+
owners: z
|
|
32
|
+
.number()
|
|
33
|
+
.int()
|
|
34
|
+
.min(1)
|
|
35
|
+
.max(50)
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Max per-owner load rows to return (default 12)."),
|
|
38
|
+
orphans: z
|
|
39
|
+
.number()
|
|
40
|
+
.int()
|
|
41
|
+
.min(1)
|
|
42
|
+
.max(100)
|
|
43
|
+
.optional()
|
|
44
|
+
.describe("Max orphan rows to return (default 25)."),
|
|
45
|
+
}, async (args) => {
|
|
46
|
+
const slug = await resolveToolSlug(args.slug);
|
|
47
|
+
const qs = new URLSearchParams();
|
|
48
|
+
if (args.bottlenecks !== undefined)
|
|
49
|
+
qs.set("bottlenecks", String(args.bottlenecks));
|
|
50
|
+
if (args.owners !== undefined)
|
|
51
|
+
qs.set("owners", String(args.owners));
|
|
52
|
+
if (args.orphans !== undefined)
|
|
53
|
+
qs.set("orphans", String(args.orphans));
|
|
54
|
+
const suffix = qs.toString() ? "?" + qs.toString() : "";
|
|
55
|
+
return jsonResult(await get(`/agent-os/${slug}/graph/query${suffix}`));
|
|
56
|
+
});
|
|
57
|
+
register("agent_os_graph_view", [
|
|
58
|
+
"Steer the human's open 3D web view (shared focus) — fly the camera to a node, filter, or reset,",
|
|
59
|
+
"so you and the user are provably looking at the same thing.",
|
|
60
|
+
"kind=focus needs nodeId (operational graph id, e.g. 'task:abc'); kind=filter sets which type/status",
|
|
61
|
+
"buckets are hidden; kind=reset clears focus + filters; kind=highlight focuses without isolating.",
|
|
62
|
+
"Takes effect only while the user has the 3D Web tab open (delivered over SSE).",
|
|
63
|
+
"Requires Redis in multi-instance/serverless prod to fan out; single-instance dev works without it.",
|
|
64
|
+
].join(" "), {
|
|
65
|
+
slug: z.string().optional().describe("AgentOS slug. Defaults to env/primary."),
|
|
66
|
+
kind: z
|
|
67
|
+
.enum(["focus", "filter", "reset", "highlight"])
|
|
68
|
+
.describe("focus | highlight (camera) · filter (hide buckets) · reset (clear)."),
|
|
69
|
+
nodeId: z
|
|
70
|
+
.string()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Target operational-graph node id for focus/highlight (e.g. 'task:abc123')."),
|
|
73
|
+
hiddenKinds: z
|
|
74
|
+
.array(z.string())
|
|
75
|
+
.optional()
|
|
76
|
+
.describe("For kind=filter: node kinds to hide (e.g. ['repo_file']). [] clears."),
|
|
77
|
+
hiddenStatuses: z
|
|
78
|
+
.array(z.string())
|
|
79
|
+
.optional()
|
|
80
|
+
.describe("For kind=filter: statuses to hide (e.g. ['done']). [] clears."),
|
|
81
|
+
}, async (args) => {
|
|
82
|
+
const slug = await resolveToolSlug(args.slug);
|
|
83
|
+
return jsonResult(await post(`/agent-os/${slug}/graph/view`, {
|
|
84
|
+
kind: args.kind,
|
|
85
|
+
nodeId: args.nodeId,
|
|
86
|
+
hiddenKinds: args.hiddenKinds,
|
|
87
|
+
hiddenStatuses: args.hiddenStatuses,
|
|
88
|
+
source: "agent",
|
|
89
|
+
}));
|
|
90
|
+
});
|
|
91
|
+
}
|
package/dist/tools/plans.js
CHANGED
|
@@ -18,7 +18,11 @@ const planStatus = z.enum([
|
|
|
18
18
|
"archived",
|
|
19
19
|
"superseded",
|
|
20
20
|
]);
|
|
21
|
-
const planPriority = z
|
|
21
|
+
const planPriority = z
|
|
22
|
+
.enum(["low", "normal", "high", "critical"])
|
|
23
|
+
.describe("Priority — default 'normal'. Most plans are 'normal'; routine is 'low'. Use 'high' only for genuinely " +
|
|
24
|
+
"urgent+important plans and 'critical' ONLY for true emergencies blocking the mission now (very few). " +
|
|
25
|
+
"Over-tagging destroys the signal — if everything is critical, nothing is.");
|
|
22
26
|
const planLinkTarget = z.enum([
|
|
23
27
|
"goal",
|
|
24
28
|
"project",
|
package/dist/tools/tasks.js
CHANGED
|
@@ -7,17 +7,32 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { get, post, patch } from "../lib/kynver-client.js";
|
|
10
|
-
const taskStatus = z
|
|
10
|
+
const taskStatus = z
|
|
11
|
+
.enum([
|
|
11
12
|
"queued",
|
|
13
|
+
"ready",
|
|
12
14
|
"running",
|
|
15
|
+
"waiting",
|
|
16
|
+
"scheduled",
|
|
13
17
|
"blocked",
|
|
14
18
|
"needs_input",
|
|
15
19
|
"awaiting_review",
|
|
16
20
|
"done",
|
|
17
21
|
"failed",
|
|
18
22
|
"cancelled",
|
|
19
|
-
])
|
|
20
|
-
|
|
23
|
+
])
|
|
24
|
+
.describe("Work-state lifecycle. `ready` = admitted, can start now (the real 'queued' — which survives as a legacy alias). " +
|
|
25
|
+
"`running` = an executor holds a live lease. `waiting` = gated on upstream tasks (set dependsOnTaskIds; auto-promotes " +
|
|
26
|
+
"to ready when they're all done). `scheduled` = deferred to a time (set scheduledFor; auto-promotes to ready when it " +
|
|
27
|
+
"passes). `blocked`/`needs_input` = a human must resolve. `awaiting_review` = review gate open. Don't hand-set " +
|
|
28
|
+
"ready→running; the dispatcher/executor lease owns that.");
|
|
29
|
+
const taskPriority = z
|
|
30
|
+
.enum(["low", "normal", "high", "critical"])
|
|
31
|
+
.describe("Priority — default 'normal'. Create coding/implementation tasks as 'normal' (routine/cleanup 'low'); " +
|
|
32
|
+
"do NOT inherit the parent plan's priority — a task on a critical plan is still 'normal'. A task only " +
|
|
33
|
+
"becomes 'critical' once it is actively BLOCKING progress (and the system already marks blocked tasks " +
|
|
34
|
+
"critical automatically). Reserve manual 'high'/'critical' for genuine urgency. If everything is " +
|
|
35
|
+
"critical, nothing is — keep most tasks at normal/low.");
|
|
21
36
|
const taskExecutor = z.enum(["inline", "harness", "acp", "manual"]);
|
|
22
37
|
const taskEventType = z.enum([
|
|
23
38
|
"created",
|
|
@@ -36,12 +51,23 @@ const personaSlug = z
|
|
|
36
51
|
.nullable()
|
|
37
52
|
.optional()
|
|
38
53
|
.describe("Lane-expert worker slug to attribute the task to, or null to clear/filter unassigned tasks.");
|
|
54
|
+
const scheduledFor = z
|
|
55
|
+
.string()
|
|
56
|
+
.nullable()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe("ISO-8601 timestamp to defer the task to. A future time creates the task as `scheduled`; the operator loop " +
|
|
59
|
+
"auto-promotes it to `ready` once the time passes. null clears the schedule.");
|
|
60
|
+
const dependsOnTaskIds = z
|
|
61
|
+
.array(z.string())
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("Upstream task ids this task waits on. Creates the task as `waiting`; the operator loop auto-promotes it to " +
|
|
64
|
+
"`ready` once every listed task is `done` (a failed/cancelled upstream keeps it waiting).");
|
|
39
65
|
export function registerTaskTools({ register, resolveToolSlug, jsonResult, compact, }) {
|
|
40
66
|
const slugField = z
|
|
41
67
|
.string()
|
|
42
68
|
.optional()
|
|
43
69
|
.describe("AgentOS slug. Omit to use env or the server-discovered primary.");
|
|
44
|
-
register("agent_os_task_create", "Create an AgentTask on the board. Idempotent within the AgentOS: pass idempotencyKey (or requestId) from the foreground turn so a Telegram retry or Ghost restart returns the existing task instead of spawning a duplicate. Response includes `created` (false = an existing task was returned).", {
|
|
70
|
+
register("agent_os_task_create", "Create an AgentTask on the board. New tasks start `ready` (dispatchable now) unless you defer them: pass scheduledFor for a timed start (→ `scheduled`) or dependsOnTaskIds to gate on upstream work (→ `waiting`); both auto-promote to `ready` when their gate clears. Idempotent within the AgentOS: pass idempotencyKey (or requestId) from the foreground turn so a Telegram retry or Ghost restart returns the existing task instead of spawning a duplicate. Response includes `created` (false = an existing task was returned).", {
|
|
45
71
|
title: z.string().describe("Short task title (required)."),
|
|
46
72
|
description: z.string().optional(),
|
|
47
73
|
priority: taskPriority.optional(),
|
|
@@ -51,6 +77,8 @@ export function registerTaskTools({ register, resolveToolSlug, jsonResult, compa
|
|
|
51
77
|
goalId: z.string().optional(),
|
|
52
78
|
projectId: z.string().optional(),
|
|
53
79
|
personaSlug,
|
|
80
|
+
scheduledFor,
|
|
81
|
+
dependsOnTaskIds,
|
|
54
82
|
idempotencyKey: z.string().optional().describe("Dedupe key from the foreground turn. Strongly recommended."),
|
|
55
83
|
requestId: z.string().optional().describe("Raw foreground request id; used as the dedupe key if idempotencyKey is absent."),
|
|
56
84
|
slug: slugField,
|
|
@@ -86,7 +114,7 @@ export function registerTaskTools({ register, resolveToolSlug, jsonResult, compa
|
|
|
86
114
|
const s = await resolveToolSlug(args.slug);
|
|
87
115
|
return jsonResult(await get(`/agent-os/${s}/tasks${qs ? `?${qs}` : ""}`));
|
|
88
116
|
});
|
|
89
|
-
register("agent_os_task_update", "Patch an AgentTask: status, priority, executor, links, progress summary, blocker, or first-class artifact refs (branch/worktreePath/prUrl/headCommit). Does not touch lease fields — use claim/renew for those.", {
|
|
117
|
+
register("agent_os_task_update", "Patch an AgentTask: status, priority, executor, links, schedule (scheduledFor), dependencies (dependsOnTaskIds), progress summary, blocker, or first-class artifact refs (branch/worktreePath/prUrl/headCommit). Does not touch lease fields — use claim/renew for those.", {
|
|
90
118
|
taskId: z.string(),
|
|
91
119
|
title: z.string().optional(),
|
|
92
120
|
description: z.string().optional(),
|
|
@@ -98,6 +126,8 @@ export function registerTaskTools({ register, resolveToolSlug, jsonResult, compa
|
|
|
98
126
|
goalId: z.string().optional(),
|
|
99
127
|
projectId: z.string().optional(),
|
|
100
128
|
personaSlug,
|
|
129
|
+
scheduledFor,
|
|
130
|
+
dependsOnTaskIds,
|
|
101
131
|
lastSummary: z.string().optional().describe("Latest progress summary."),
|
|
102
132
|
blocker: z.string().optional(),
|
|
103
133
|
branch: z.string().optional(),
|
package/package.json
CHANGED