@dobbyai/mcp-external 1.0.3 → 1.1.0
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/__tests__/agent-mail-tools.test.d.ts +8 -0
- package/dist/__tests__/agent-mail-tools.test.d.ts.map +1 -0
- package/dist/__tests__/agent-mail-tools.test.js +262 -0
- package/dist/__tests__/agent-mail-tools.test.js.map +1 -0
- package/dist/__tests__/annotations.test.d.ts +8 -0
- package/dist/__tests__/annotations.test.d.ts.map +1 -0
- package/dist/__tests__/annotations.test.js +108 -0
- package/dist/__tests__/annotations.test.js.map +1 -0
- package/dist/__tests__/auth.test.d.ts +7 -0
- package/dist/__tests__/auth.test.d.ts.map +1 -0
- package/dist/__tests__/auth.test.js +116 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/integration/protocol.test.d.ts +8 -0
- package/dist/__tests__/integration/protocol.test.d.ts.map +1 -0
- package/dist/__tests__/integration/protocol.test.js +104 -0
- package/dist/__tests__/integration/protocol.test.js.map +1 -0
- package/dist/__tests__/mcp-integrations.test.d.ts +8 -0
- package/dist/__tests__/mcp-integrations.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-integrations.test.js +375 -0
- package/dist/__tests__/mcp-integrations.test.js.map +1 -0
- package/dist/__tests__/memory-graph-tools.test.d.ts +8 -0
- package/dist/__tests__/memory-graph-tools.test.d.ts.map +1 -0
- package/dist/__tests__/memory-graph-tools.test.js +265 -0
- package/dist/__tests__/memory-graph-tools.test.js.map +1 -0
- package/dist/__tests__/schedule-tools.test.d.ts +8 -0
- package/dist/__tests__/schedule-tools.test.d.ts.map +1 -0
- package/dist/__tests__/schedule-tools.test.js +290 -0
- package/dist/__tests__/schedule-tools.test.js.map +1 -0
- package/dist/__tests__/tiers.test.d.ts +7 -0
- package/dist/__tests__/tiers.test.d.ts.map +1 -0
- package/dist/__tests__/tiers.test.js +103 -0
- package/dist/__tests__/tiers.test.js.map +1 -0
- package/dist/__tests__/tools.test.d.ts +7 -0
- package/dist/__tests__/tools.test.d.ts.map +1 -0
- package/dist/__tests__/tools.test.js +143 -0
- package/dist/__tests__/tools.test.js.map +1 -0
- package/dist/__tests__/transport.test.d.ts +7 -0
- package/dist/__tests__/transport.test.d.ts.map +1 -0
- package/dist/__tests__/transport.test.js +55 -0
- package/dist/__tests__/transport.test.js.map +1 -0
- package/dist/__tests__/web-eval-tools.test.d.ts +8 -0
- package/dist/__tests__/web-eval-tools.test.d.ts.map +1 -0
- package/dist/__tests__/web-eval-tools.test.js +252 -0
- package/dist/__tests__/web-eval-tools.test.js.map +1 -0
- package/dist/__tests__/workflow-tools.test.d.ts +8 -0
- package/dist/__tests__/workflow-tools.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-tools.test.js +268 -0
- package/dist/__tests__/workflow-tools.test.js.map +1 -0
- package/dist/auth/oauth-provider.d.ts +34 -0
- package/dist/auth/oauth-provider.d.ts.map +1 -0
- package/dist/auth/oauth-provider.js +75 -0
- package/dist/auth/oauth-provider.js.map +1 -0
- package/dist/auth/token-verifier.d.ts +40 -0
- package/dist/auth/token-verifier.d.ts.map +1 -0
- package/dist/auth/token-verifier.js +138 -0
- package/dist/auth/token-verifier.js.map +1 -0
- package/dist/http-server.d.ts +35 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +175 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.js +131 -36
- package/dist/index.js.map +1 -1
- package/dist/lib/dobby-client.d.ts +50 -20
- package/dist/lib/dobby-client.d.ts.map +1 -1
- package/dist/lib/dobby-client.js +50 -0
- package/dist/lib/dobby-client.js.map +1 -1
- package/dist/tools/agent-mail.d.ts +153 -0
- package/dist/tools/agent-mail.d.ts.map +1 -0
- package/dist/tools/agent-mail.js +340 -0
- package/dist/tools/agent-mail.js.map +1 -0
- package/dist/tools/approvals.d.ts +24 -0
- package/dist/tools/approvals.d.ts.map +1 -1
- package/dist/tools/approvals.js +24 -0
- package/dist/tools/approvals.js.map +1 -1
- package/dist/tools/crew-builder.d.ts +24 -0
- package/dist/tools/crew-builder.d.ts.map +1 -1
- package/dist/tools/crew-builder.js +24 -0
- package/dist/tools/crew-builder.js.map +1 -1
- package/dist/tools/crewai.d.ts +24 -0
- package/dist/tools/crewai.d.ts.map +1 -1
- package/dist/tools/crewai.js +24 -0
- package/dist/tools/crewai.js.map +1 -1
- package/dist/tools/exa.d.ts +161 -0
- package/dist/tools/exa.d.ts.map +1 -0
- package/dist/tools/exa.js +228 -0
- package/dist/tools/exa.js.map +1 -0
- package/dist/tools/github-mcp.d.ts +303 -0
- package/dist/tools/github-mcp.d.ts.map +1 -0
- package/dist/tools/github-mcp.js +397 -0
- package/dist/tools/github-mcp.js.map +1 -0
- package/dist/tools/governance.d.ts +129 -0
- package/dist/tools/governance.d.ts.map +1 -0
- package/dist/tools/governance.js +171 -0
- package/dist/tools/governance.js.map +1 -0
- package/dist/tools/index.d.ts +3589 -159
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +250 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/jira.d.ts +60 -0
- package/dist/tools/jira.d.ts.map +1 -1
- package/dist/tools/jira.js +60 -0
- package/dist/tools/jira.js.map +1 -1
- package/dist/tools/knowledge-base.d.ts +144 -0
- package/dist/tools/knowledge-base.d.ts.map +1 -0
- package/dist/tools/knowledge-base.js +179 -0
- package/dist/tools/knowledge-base.js.map +1 -0
- package/dist/tools/mcp-metrics.d.ts +62 -0
- package/dist/tools/mcp-metrics.d.ts.map +1 -0
- package/dist/tools/mcp-metrics.js +270 -0
- package/dist/tools/mcp-metrics.js.map +1 -0
- package/dist/tools/mcp-tools.d.ts +12 -0
- package/dist/tools/mcp-tools.d.ts.map +1 -1
- package/dist/tools/mcp-tools.js +12 -0
- package/dist/tools/mcp-tools.js.map +1 -1
- package/dist/tools/mem0.d.ts +168 -0
- package/dist/tools/mem0.d.ts.map +1 -0
- package/dist/tools/mem0.js +255 -0
- package/dist/tools/mem0.js.map +1 -0
- package/dist/tools/memory-graph.d.ts +197 -0
- package/dist/tools/memory-graph.d.ts.map +1 -0
- package/dist/tools/memory-graph.js +545 -0
- package/dist/tools/memory-graph.js.map +1 -0
- package/dist/tools/messages.d.ts +12 -0
- package/dist/tools/messages.d.ts.map +1 -1
- package/dist/tools/messages.js +12 -0
- package/dist/tools/messages.js.map +1 -1
- package/dist/tools/moltbook.d.ts +564 -0
- package/dist/tools/moltbook.d.ts.map +1 -0
- package/dist/tools/moltbook.js +792 -0
- package/dist/tools/moltbook.js.map +1 -0
- package/dist/tools/ops.d.ts +219 -0
- package/dist/tools/ops.d.ts.map +1 -0
- package/dist/tools/ops.js +360 -0
- package/dist/tools/ops.js.map +1 -0
- package/dist/tools/schedules.d.ts +196 -0
- package/dist/tools/schedules.d.ts.map +1 -0
- package/dist/tools/schedules.js +264 -0
- package/dist/tools/schedules.js.map +1 -0
- package/dist/tools/services.d.ts +6 -0
- package/dist/tools/services.d.ts.map +1 -1
- package/dist/tools/services.js +6 -0
- package/dist/tools/services.js.map +1 -1
- package/dist/tools/tasks.d.ts +45 -0
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +49 -4
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/tiers.d.ts +39 -0
- package/dist/tools/tiers.d.ts.map +1 -0
- package/dist/tools/tiers.js +138 -0
- package/dist/tools/tiers.js.map +1 -0
- package/dist/tools/unified-agents.d.ts +62 -0
- package/dist/tools/unified-agents.d.ts.map +1 -0
- package/dist/tools/unified-agents.js +147 -0
- package/dist/tools/unified-agents.js.map +1 -0
- package/dist/tools/web-eval.d.ts +172 -0
- package/dist/tools/web-eval.d.ts.map +1 -0
- package/dist/tools/web-eval.js +347 -0
- package/dist/tools/web-eval.js.map +1 -0
- package/dist/tools/workflow.d.ts +171 -0
- package/dist/tools/workflow.d.ts.map +1 -0
- package/dist/tools/workflow.js +518 -0
- package/dist/tools/workflow.js.map +1 -0
- package/package.json +8 -3
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Automation MCP Tools
|
|
3
|
+
*
|
|
4
|
+
* Phase 2: Intelligent task routing and auto-assignment.
|
|
5
|
+
* Provides tools for task classification, agent workload monitoring,
|
|
6
|
+
* and automated/manual assignment through the Dobby platform.
|
|
7
|
+
*/
|
|
8
|
+
import { DobbyClient } from '../lib/dobby-client.js';
|
|
9
|
+
export declare const workflowTools: {
|
|
10
|
+
workflow_classify_task: {
|
|
11
|
+
name: string;
|
|
12
|
+
annotations: {
|
|
13
|
+
title: string;
|
|
14
|
+
readOnlyHint: boolean;
|
|
15
|
+
destructiveHint: boolean;
|
|
16
|
+
openWorldHint: boolean;
|
|
17
|
+
};
|
|
18
|
+
description: string;
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object";
|
|
21
|
+
properties: {
|
|
22
|
+
title: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
description: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
priority: {
|
|
31
|
+
type: string;
|
|
32
|
+
enum: string[];
|
|
33
|
+
description: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
required: string[];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
workflow_auto_assign: {
|
|
40
|
+
name: string;
|
|
41
|
+
annotations: {
|
|
42
|
+
title: string;
|
|
43
|
+
readOnlyHint: boolean;
|
|
44
|
+
destructiveHint: boolean;
|
|
45
|
+
openWorldHint: boolean;
|
|
46
|
+
};
|
|
47
|
+
description: string;
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: "object";
|
|
50
|
+
properties: {
|
|
51
|
+
task_id: {
|
|
52
|
+
type: string;
|
|
53
|
+
description: string;
|
|
54
|
+
pattern: string;
|
|
55
|
+
};
|
|
56
|
+
title: {
|
|
57
|
+
type: string;
|
|
58
|
+
description: string;
|
|
59
|
+
};
|
|
60
|
+
description: {
|
|
61
|
+
type: string;
|
|
62
|
+
description: string;
|
|
63
|
+
};
|
|
64
|
+
priority: {
|
|
65
|
+
type: string;
|
|
66
|
+
enum: string[];
|
|
67
|
+
description: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
required: string[];
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
workflow_agent_workload: {
|
|
74
|
+
name: string;
|
|
75
|
+
annotations: {
|
|
76
|
+
title: string;
|
|
77
|
+
readOnlyHint: boolean;
|
|
78
|
+
destructiveHint: boolean;
|
|
79
|
+
openWorldHint: boolean;
|
|
80
|
+
};
|
|
81
|
+
description: string;
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object";
|
|
84
|
+
properties: {
|
|
85
|
+
agent_layer: {
|
|
86
|
+
type: string;
|
|
87
|
+
enum: string[];
|
|
88
|
+
description: string;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
workflow_assignment_rules: {
|
|
94
|
+
name: string;
|
|
95
|
+
annotations: {
|
|
96
|
+
title: string;
|
|
97
|
+
readOnlyHint: boolean;
|
|
98
|
+
destructiveHint: boolean;
|
|
99
|
+
openWorldHint: boolean;
|
|
100
|
+
};
|
|
101
|
+
description: string;
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: "object";
|
|
104
|
+
properties: {
|
|
105
|
+
active_only: {
|
|
106
|
+
type: string;
|
|
107
|
+
description: string;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
export declare function handleWorkflowClassifyTask(client: DobbyClient, args: {
|
|
114
|
+
title: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
priority?: string;
|
|
117
|
+
}): Promise<{
|
|
118
|
+
content: {
|
|
119
|
+
type: "text";
|
|
120
|
+
text: string;
|
|
121
|
+
}[];
|
|
122
|
+
}>;
|
|
123
|
+
export declare function handleWorkflowAutoAssign(client: DobbyClient, args: {
|
|
124
|
+
task_id: string;
|
|
125
|
+
title: string;
|
|
126
|
+
description?: string;
|
|
127
|
+
priority?: string;
|
|
128
|
+
}): Promise<{
|
|
129
|
+
content: {
|
|
130
|
+
type: "text";
|
|
131
|
+
text: string;
|
|
132
|
+
}[];
|
|
133
|
+
isError: boolean;
|
|
134
|
+
} | {
|
|
135
|
+
content: {
|
|
136
|
+
type: "text";
|
|
137
|
+
text: string;
|
|
138
|
+
}[];
|
|
139
|
+
isError?: undefined;
|
|
140
|
+
}>;
|
|
141
|
+
export declare function handleWorkflowAgentWorkload(client: DobbyClient, args: {
|
|
142
|
+
agent_layer?: string;
|
|
143
|
+
}): Promise<{
|
|
144
|
+
content: {
|
|
145
|
+
type: "text";
|
|
146
|
+
text: string;
|
|
147
|
+
}[];
|
|
148
|
+
isError: boolean;
|
|
149
|
+
} | {
|
|
150
|
+
content: {
|
|
151
|
+
type: "text";
|
|
152
|
+
text: string;
|
|
153
|
+
}[];
|
|
154
|
+
isError?: undefined;
|
|
155
|
+
}>;
|
|
156
|
+
export declare function handleWorkflowAssignmentRules(client: DobbyClient, args: {
|
|
157
|
+
active_only?: boolean;
|
|
158
|
+
}): Promise<{
|
|
159
|
+
content: {
|
|
160
|
+
type: "text";
|
|
161
|
+
text: string;
|
|
162
|
+
}[];
|
|
163
|
+
isError: boolean;
|
|
164
|
+
} | {
|
|
165
|
+
content: {
|
|
166
|
+
type: "text";
|
|
167
|
+
text: string;
|
|
168
|
+
}[];
|
|
169
|
+
isError?: undefined;
|
|
170
|
+
}>;
|
|
171
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/tools/workflow.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAkJrD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0GzB,CAAC;AAuFF,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;GA2BjE;AAqBD,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;GA6FlF;AAmCD,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;GA2C/B;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;GA6ChC"}
|
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Automation MCP Tools
|
|
3
|
+
*
|
|
4
|
+
* Phase 2: Intelligent task routing and auto-assignment.
|
|
5
|
+
* Provides tools for task classification, agent workload monitoring,
|
|
6
|
+
* and automated/manual assignment through the Dobby platform.
|
|
7
|
+
*/
|
|
8
|
+
// ============================================
|
|
9
|
+
// Task Category Definitions (mirrors Python)
|
|
10
|
+
// ============================================
|
|
11
|
+
const CATEGORY_KEYWORDS = {
|
|
12
|
+
backend: [
|
|
13
|
+
'api', 'endpoint', 'route', 'fastapi', 'server', 'backend',
|
|
14
|
+
'middleware', 'handler', 'service', 'controller', 'python',
|
|
15
|
+
'async', 'uvicorn', 'pydantic',
|
|
16
|
+
],
|
|
17
|
+
frontend: [
|
|
18
|
+
'ui', 'frontend', 'react', 'component', 'page', 'layout',
|
|
19
|
+
'css', 'tailwind', 'next.js', 'nextjs', 'html', 'form',
|
|
20
|
+
'modal', 'dialog', 'button', 'sidebar', 'dashboard',
|
|
21
|
+
],
|
|
22
|
+
api: [
|
|
23
|
+
'rest', 'graphql', 'webhook', 'cors', 'openapi', 'swagger',
|
|
24
|
+
'rate limit', 'throttle', 'api route', 'api key',
|
|
25
|
+
],
|
|
26
|
+
database: [
|
|
27
|
+
'bigquery', 'sql', 'query', 'migration', 'schema', 'table',
|
|
28
|
+
'column', 'index', 'partition', 'cluster', 'database',
|
|
29
|
+
],
|
|
30
|
+
security: [
|
|
31
|
+
'auth', 'authentication', 'authorization', 'sso', 'saml',
|
|
32
|
+
'oidc', 'oauth', 'token', 'permission', 'rbac', 'encrypt',
|
|
33
|
+
'vulnerability', 'security', 'xss', 'csrf', 'injection',
|
|
34
|
+
],
|
|
35
|
+
testing: [
|
|
36
|
+
'test', 'vitest', 'pytest', 'e2e', 'playwright', 'coverage',
|
|
37
|
+
'mock', 'fixture', 'assertion', 'spec', 'unit test',
|
|
38
|
+
],
|
|
39
|
+
devops: [
|
|
40
|
+
'deploy', 'ci/cd', 'docker', 'kubernetes', 'helm', 'github actions',
|
|
41
|
+
'pipeline', 'build', 'release', 'monitoring', 'logging',
|
|
42
|
+
],
|
|
43
|
+
docs: [
|
|
44
|
+
'documentation', 'readme', 'docs', 'comment', 'jsdoc',
|
|
45
|
+
'docstring', 'guide', 'tutorial', 'changelog',
|
|
46
|
+
],
|
|
47
|
+
planning: [
|
|
48
|
+
'plan', 'design', 'architecture', 'roadmap', 'requirement',
|
|
49
|
+
'spec', 'rfc', 'adr', 'decision',
|
|
50
|
+
],
|
|
51
|
+
refactor: [
|
|
52
|
+
'refactor', 'cleanup', 'technical debt', 'optimize',
|
|
53
|
+
'performance', 'simplify', 'restructure', 'modernize',
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
let categoryAgentMapCache = null;
|
|
57
|
+
let categoryAgentMapCacheTime = 0;
|
|
58
|
+
const CATEGORY_MAP_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
59
|
+
function getDefaultCategoryAgentMap() {
|
|
60
|
+
return {
|
|
61
|
+
backend: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-backend-agent' },
|
|
62
|
+
frontend: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-frontend-agent' },
|
|
63
|
+
api: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-api-agent' },
|
|
64
|
+
database: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-database-agent' },
|
|
65
|
+
security: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-security-agent' },
|
|
66
|
+
testing: { coordinator: 'dobby-qa-lead-agent', worker: 'dobby-test-writer-agent' },
|
|
67
|
+
devops: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-devops-agent' },
|
|
68
|
+
docs: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-docs-agent' },
|
|
69
|
+
planning: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-planning-agent' },
|
|
70
|
+
refactor: { coordinator: 'dobby-dev-coordinator-agent', worker: 'dobby-refactor-agent' },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const AGENT_NAME_TO_CATEGORY = {
|
|
74
|
+
'backend': ['backend'],
|
|
75
|
+
'frontend': ['frontend'],
|
|
76
|
+
'api': ['api'],
|
|
77
|
+
'database': ['database'],
|
|
78
|
+
'security': ['security'],
|
|
79
|
+
'test-writer': ['testing'],
|
|
80
|
+
'devops': ['devops'],
|
|
81
|
+
'docs': ['docs'],
|
|
82
|
+
'planning': ['planning'],
|
|
83
|
+
'refactor': ['refactor'],
|
|
84
|
+
};
|
|
85
|
+
async function getCategoryAgentMap(client) {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
if (categoryAgentMapCache && (now - categoryAgentMapCacheTime) < CATEGORY_MAP_CACHE_TTL) {
|
|
88
|
+
return categoryAgentMapCache;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const data = await client.request(`/api/v1/tenants/${client.tenantId}/unified-agents`);
|
|
92
|
+
const agents = data?.data?.agents || data?.agents || [];
|
|
93
|
+
const map = { ...getDefaultCategoryAgentMap() };
|
|
94
|
+
for (const agent of agents) {
|
|
95
|
+
const agentId = agent.agent_id || agent.unified_id || '';
|
|
96
|
+
const layer = agent.agent_layer || '';
|
|
97
|
+
const group = agent.group || '';
|
|
98
|
+
// Map coordinators by group
|
|
99
|
+
if (layer === 'coordinator') {
|
|
100
|
+
for (const [category, agentMap] of Object.entries(map)) {
|
|
101
|
+
if (group === 'qa' && category === 'testing') {
|
|
102
|
+
agentMap.coordinator = agentId;
|
|
103
|
+
}
|
|
104
|
+
else if (group === 'dev' && category !== 'testing') {
|
|
105
|
+
agentMap.coordinator = agentId;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Map workers by name matching
|
|
110
|
+
if (layer === 'worker') {
|
|
111
|
+
for (const [nameFragment, categories] of Object.entries(AGENT_NAME_TO_CATEGORY)) {
|
|
112
|
+
if (agentId.includes(nameFragment)) {
|
|
113
|
+
for (const cat of categories) {
|
|
114
|
+
if (map[cat]) {
|
|
115
|
+
map[cat].worker = agentId;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
categoryAgentMapCache = map;
|
|
123
|
+
categoryAgentMapCacheTime = now;
|
|
124
|
+
return map;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return getDefaultCategoryAgentMap();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// ============================================
|
|
131
|
+
// Tool Definitions
|
|
132
|
+
// ============================================
|
|
133
|
+
export const workflowTools = {
|
|
134
|
+
workflow_classify_task: {
|
|
135
|
+
name: 'workflow_classify_task',
|
|
136
|
+
annotations: {
|
|
137
|
+
title: 'Classify Task',
|
|
138
|
+
readOnlyHint: true,
|
|
139
|
+
destructiveHint: false,
|
|
140
|
+
openWorldHint: false,
|
|
141
|
+
},
|
|
142
|
+
description: 'Classify a task and get an auto-assignment suggestion. Analyzes task title and description to determine the best agent. Does NOT execute the assignment — use workflow_auto_assign to apply.',
|
|
143
|
+
inputSchema: {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: {
|
|
146
|
+
title: {
|
|
147
|
+
type: 'string',
|
|
148
|
+
description: 'Task title to classify',
|
|
149
|
+
},
|
|
150
|
+
description: {
|
|
151
|
+
type: 'string',
|
|
152
|
+
description: 'Optional: Task description for better classification',
|
|
153
|
+
},
|
|
154
|
+
priority: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
enum: ['low', 'medium', 'high'],
|
|
157
|
+
description: 'Task priority (default: medium)',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
required: ['title'],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
workflow_auto_assign: {
|
|
164
|
+
name: 'workflow_auto_assign',
|
|
165
|
+
annotations: {
|
|
166
|
+
title: 'Auto-Assign Task',
|
|
167
|
+
readOnlyHint: false,
|
|
168
|
+
destructiveHint: true,
|
|
169
|
+
openWorldHint: false,
|
|
170
|
+
},
|
|
171
|
+
description: 'Auto-assign a task to the best agent based on classification and workload. Calls the Dobby API to execute the assignment.',
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
task_id: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
description: 'Task ID to assign (format: task_xxxxx)',
|
|
178
|
+
pattern: '^task_[a-zA-Z0-9_-]+$',
|
|
179
|
+
},
|
|
180
|
+
title: {
|
|
181
|
+
type: 'string',
|
|
182
|
+
description: 'Task title (used for classification if not already classified)',
|
|
183
|
+
},
|
|
184
|
+
description: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'Optional: Task description',
|
|
187
|
+
},
|
|
188
|
+
priority: {
|
|
189
|
+
type: 'string',
|
|
190
|
+
enum: ['low', 'medium', 'high'],
|
|
191
|
+
description: 'Task priority (default: medium)',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
required: ['task_id', 'title'],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
workflow_agent_workload: {
|
|
198
|
+
name: 'workflow_agent_workload',
|
|
199
|
+
annotations: {
|
|
200
|
+
title: 'Agent Workload',
|
|
201
|
+
readOnlyHint: true,
|
|
202
|
+
destructiveHint: false,
|
|
203
|
+
openWorldHint: false,
|
|
204
|
+
},
|
|
205
|
+
description: 'View current agent workload across the team. Shows active tasks, availability, and success rates.',
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
agent_layer: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
enum: ['coordinator', 'worker', 'all'],
|
|
212
|
+
description: 'Filter by agent layer (default: all)',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
workflow_assignment_rules: {
|
|
218
|
+
name: 'workflow_assignment_rules',
|
|
219
|
+
annotations: {
|
|
220
|
+
title: 'Assignment Rules',
|
|
221
|
+
readOnlyHint: true,
|
|
222
|
+
destructiveHint: false,
|
|
223
|
+
openWorldHint: false,
|
|
224
|
+
},
|
|
225
|
+
description: 'List configured assignment rules for the current tenant. Rules override default keyword-based routing.',
|
|
226
|
+
inputSchema: {
|
|
227
|
+
type: 'object',
|
|
228
|
+
properties: {
|
|
229
|
+
active_only: {
|
|
230
|
+
type: 'boolean',
|
|
231
|
+
description: 'Only show active rules (default: true)',
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
async function classifyTask(client, title, description = '', _priority = 'medium') {
|
|
238
|
+
const text = `${title} ${description}`.toLowerCase();
|
|
239
|
+
const agentMap = await getCategoryAgentMap(client);
|
|
240
|
+
const scores = {};
|
|
241
|
+
for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {
|
|
242
|
+
const matched = [];
|
|
243
|
+
for (const kw of keywords) {
|
|
244
|
+
const pattern = new RegExp(`\\b${kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i');
|
|
245
|
+
if (pattern.test(text)) {
|
|
246
|
+
matched.push(kw);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (matched.length > 0) {
|
|
250
|
+
let score = matched.length / keywords.length;
|
|
251
|
+
// Boost for title matches
|
|
252
|
+
const titleLower = title.toLowerCase();
|
|
253
|
+
const titleMatches = matched.filter(kw => {
|
|
254
|
+
const pat = new RegExp(`\\b${kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i');
|
|
255
|
+
return pat.test(titleLower);
|
|
256
|
+
}).length;
|
|
257
|
+
if (titleMatches > 0) {
|
|
258
|
+
score += titleMatches * 0.15;
|
|
259
|
+
}
|
|
260
|
+
scores[category] = { score: Math.min(score, 1.0), matched };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const defaultMap = agentMap['backend'] || getDefaultCategoryAgentMap()['backend'];
|
|
264
|
+
if (Object.keys(scores).length === 0) {
|
|
265
|
+
return {
|
|
266
|
+
category: 'backend',
|
|
267
|
+
subcategory: null,
|
|
268
|
+
confidence: 0.3,
|
|
269
|
+
matched_keywords: [],
|
|
270
|
+
suggested_coordinator: defaultMap.coordinator,
|
|
271
|
+
suggested_worker: defaultMap.worker,
|
|
272
|
+
reasoning: 'No keywords matched — defaulting to backend development agent.',
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const bestCategory = Object.entries(scores).reduce((best, [cat, data]) => data.score > best[1].score ? [cat, data] : best)[0];
|
|
276
|
+
const { score: confidence, matched } = scores[bestCategory];
|
|
277
|
+
const categoryMapping = agentMap[bestCategory] || defaultMap;
|
|
278
|
+
return {
|
|
279
|
+
category: bestCategory,
|
|
280
|
+
subcategory: matched[0] || null,
|
|
281
|
+
confidence,
|
|
282
|
+
matched_keywords: matched.slice(0, 10),
|
|
283
|
+
suggested_coordinator: categoryMapping.coordinator,
|
|
284
|
+
suggested_worker: categoryMapping.worker,
|
|
285
|
+
reasoning: `Task classified as '${bestCategory}' (confidence: ${(confidence * 100).toFixed(0)}%). Matched keywords: ${matched.slice(0, 5).join(', ')}. Suggested: ${categoryMapping.worker} under ${categoryMapping.coordinator}.`,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// ============================================
|
|
289
|
+
// Tool Handlers
|
|
290
|
+
// ============================================
|
|
291
|
+
export async function handleWorkflowClassifyTask(client, args) {
|
|
292
|
+
const classification = await classifyTask(client, args.title, args.description || '', args.priority || 'medium');
|
|
293
|
+
let text = '## Task Classification\n\n';
|
|
294
|
+
text += `**Category:** ${classification.category}\n`;
|
|
295
|
+
text += `**Confidence:** ${(classification.confidence * 100).toFixed(0)}%\n`;
|
|
296
|
+
text += `**Coordinator:** ${classification.suggested_coordinator}\n`;
|
|
297
|
+
text += `**Worker:** ${classification.suggested_worker}\n`;
|
|
298
|
+
if (classification.matched_keywords.length > 0) {
|
|
299
|
+
text += `\n### Matched Keywords\n- ${classification.matched_keywords.join(', ')}\n`;
|
|
300
|
+
}
|
|
301
|
+
text += `\n### Next Steps\n1. Use \`workflow_auto_assign\` to execute this assignment\n`;
|
|
302
|
+
return {
|
|
303
|
+
content: [{
|
|
304
|
+
type: 'text',
|
|
305
|
+
text,
|
|
306
|
+
}],
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Helper to call Dobby API using the client's config.
|
|
311
|
+
* Uses global fetch (not client.fetch which is private).
|
|
312
|
+
*/
|
|
313
|
+
async function dobbyApiFetch(client, endpoint, options = {}) {
|
|
314
|
+
return fetch(`${client.apiUrl}${endpoint}`, {
|
|
315
|
+
...options,
|
|
316
|
+
headers: {
|
|
317
|
+
'Content-Type': 'application/json',
|
|
318
|
+
'X-API-Key': client.apiKey,
|
|
319
|
+
...options.headers,
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
export async function handleWorkflowAutoAssign(client, args) {
|
|
324
|
+
// First classify with dynamic agent map
|
|
325
|
+
const classification = await classifyTask(client, args.title, args.description || '', args.priority || 'medium');
|
|
326
|
+
// Check agent health before assignment (Task 3.5)
|
|
327
|
+
let healthWarning = null;
|
|
328
|
+
try {
|
|
329
|
+
const healthResponse = await dobbyApiFetch(client, `/api/v1/tenants/${client.tenantId}/unified-agents/${classification.suggested_worker}/health`);
|
|
330
|
+
if (healthResponse.ok) {
|
|
331
|
+
const health = await healthResponse.json();
|
|
332
|
+
const agentStatus = health.agent_status || health.status;
|
|
333
|
+
if (agentStatus === 'paused' || agentStatus === 'blocked') {
|
|
334
|
+
healthWarning = `${classification.suggested_worker} is ${agentStatus}.`;
|
|
335
|
+
// Try to find a healthy alternative in same category
|
|
336
|
+
const agentMap = await getCategoryAgentMap(client);
|
|
337
|
+
for (const [, mapping] of Object.entries(agentMap)) {
|
|
338
|
+
if (mapping.worker !== classification.suggested_worker) {
|
|
339
|
+
classification.suggested_worker = mapping.worker;
|
|
340
|
+
healthWarning += ` Routing to ${mapping.worker} instead.`;
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Health check failed — proceed with suggestion anyway
|
|
349
|
+
}
|
|
350
|
+
// Call Dobby API to execute assignment
|
|
351
|
+
try {
|
|
352
|
+
const response = await dobbyApiFetch(client, `/api/v1/tasks/${args.task_id}/auto-assign`, {
|
|
353
|
+
method: 'POST',
|
|
354
|
+
body: JSON.stringify({
|
|
355
|
+
title: args.title,
|
|
356
|
+
description: args.description || '',
|
|
357
|
+
priority: args.priority || 'medium',
|
|
358
|
+
suggested_coordinator: classification.suggested_coordinator,
|
|
359
|
+
suggested_worker: classification.suggested_worker,
|
|
360
|
+
classification,
|
|
361
|
+
}),
|
|
362
|
+
});
|
|
363
|
+
if (!response.ok) {
|
|
364
|
+
const errorText = await response.text();
|
|
365
|
+
return {
|
|
366
|
+
content: [{
|
|
367
|
+
type: 'text',
|
|
368
|
+
text: formatAutoAssignResult({
|
|
369
|
+
status: 'error',
|
|
370
|
+
error: `API error (${response.status}): ${errorText.slice(0, 200)}`,
|
|
371
|
+
classification,
|
|
372
|
+
health_warning: healthWarning,
|
|
373
|
+
}),
|
|
374
|
+
}],
|
|
375
|
+
isError: true,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const result = await response.json();
|
|
379
|
+
return {
|
|
380
|
+
content: [{
|
|
381
|
+
type: 'text',
|
|
382
|
+
text: formatAutoAssignResult({
|
|
383
|
+
status: 'assigned',
|
|
384
|
+
...result,
|
|
385
|
+
classification,
|
|
386
|
+
health_warning: healthWarning,
|
|
387
|
+
}),
|
|
388
|
+
}],
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
393
|
+
return {
|
|
394
|
+
content: [{
|
|
395
|
+
type: 'text',
|
|
396
|
+
text: formatAutoAssignResult({
|
|
397
|
+
status: 'suggestion_only',
|
|
398
|
+
note: `Could not reach Dobby API (${errMsg}). Returning local classification.`,
|
|
399
|
+
classification,
|
|
400
|
+
health_warning: healthWarning,
|
|
401
|
+
}),
|
|
402
|
+
}],
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function formatAutoAssignResult(data) {
|
|
407
|
+
const classification = data.classification;
|
|
408
|
+
const status = data.status;
|
|
409
|
+
const healthWarning = data.health_warning;
|
|
410
|
+
let text = '## Auto-Assignment Result\n\n';
|
|
411
|
+
text += `**Status:** ${status}\n`;
|
|
412
|
+
if (healthWarning) {
|
|
413
|
+
text += `**Health Warning:** ${healthWarning}\n`;
|
|
414
|
+
}
|
|
415
|
+
if (classification) {
|
|
416
|
+
text += `**Category:** ${classification.category}\n`;
|
|
417
|
+
text += `**Coordinator:** ${classification.suggested_coordinator}\n`;
|
|
418
|
+
text += `**Worker:** ${classification.suggested_worker}\n`;
|
|
419
|
+
text += `**Confidence:** ${(classification.confidence * 100).toFixed(0)}%\n`;
|
|
420
|
+
}
|
|
421
|
+
if (data.error) {
|
|
422
|
+
text += `\n### Error\n${data.error}\n`;
|
|
423
|
+
}
|
|
424
|
+
if (data.note) {
|
|
425
|
+
text += `\n### Note\n${data.note}\n`;
|
|
426
|
+
}
|
|
427
|
+
if (classification?.matched_keywords && classification.matched_keywords.length > 0) {
|
|
428
|
+
text += `\n### Matched Keywords\n- ${classification.matched_keywords.join(', ')}\n`;
|
|
429
|
+
}
|
|
430
|
+
return text;
|
|
431
|
+
}
|
|
432
|
+
export async function handleWorkflowAgentWorkload(client, args) {
|
|
433
|
+
try {
|
|
434
|
+
const layer = args.agent_layer || 'all';
|
|
435
|
+
const response = await dobbyApiFetch(client, `/api/v1/agents/workload?layer=${layer}`);
|
|
436
|
+
if (!response.ok) {
|
|
437
|
+
const errorText = await response.text();
|
|
438
|
+
return {
|
|
439
|
+
content: [{
|
|
440
|
+
type: 'text',
|
|
441
|
+
text: JSON.stringify({
|
|
442
|
+
error: `API error (${response.status}): ${errorText.slice(0, 200)}`,
|
|
443
|
+
}, null, 2),
|
|
444
|
+
}],
|
|
445
|
+
isError: true,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
const data = await response.json();
|
|
449
|
+
return {
|
|
450
|
+
content: [{
|
|
451
|
+
type: 'text',
|
|
452
|
+
text: JSON.stringify(data, null, 2),
|
|
453
|
+
}],
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
458
|
+
const agentMap = await getCategoryAgentMap(client);
|
|
459
|
+
return {
|
|
460
|
+
content: [{
|
|
461
|
+
type: 'text',
|
|
462
|
+
text: JSON.stringify({
|
|
463
|
+
note: `Could not reach Dobby API (${errMsg}). Showing agent hierarchy.`,
|
|
464
|
+
agents: Object.entries(agentMap).map(([category, agents]) => ({
|
|
465
|
+
category,
|
|
466
|
+
coordinator: agents.coordinator,
|
|
467
|
+
worker: agents.worker,
|
|
468
|
+
})),
|
|
469
|
+
}, null, 2),
|
|
470
|
+
}],
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
export async function handleWorkflowAssignmentRules(client, args) {
|
|
475
|
+
try {
|
|
476
|
+
const activeOnly = args.active_only !== false;
|
|
477
|
+
const response = await dobbyApiFetch(client, `/api/v1/workflow/assignment-rules?active_only=${activeOnly}`);
|
|
478
|
+
if (!response.ok) {
|
|
479
|
+
const errorText = await response.text();
|
|
480
|
+
return {
|
|
481
|
+
content: [{
|
|
482
|
+
type: 'text',
|
|
483
|
+
text: JSON.stringify({
|
|
484
|
+
error: `API error (${response.status}): ${errorText.slice(0, 200)}`,
|
|
485
|
+
}, null, 2),
|
|
486
|
+
}],
|
|
487
|
+
isError: true,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
const data = await response.json();
|
|
491
|
+
return {
|
|
492
|
+
content: [{
|
|
493
|
+
type: 'text',
|
|
494
|
+
text: JSON.stringify(data, null, 2),
|
|
495
|
+
}],
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
500
|
+
const agentMap = await getCategoryAgentMap(client);
|
|
501
|
+
return {
|
|
502
|
+
content: [{
|
|
503
|
+
type: 'text',
|
|
504
|
+
text: JSON.stringify({
|
|
505
|
+
note: `Could not reach Dobby API (${errMsg}). No rules available offline.`,
|
|
506
|
+
rules: [],
|
|
507
|
+
default_routing: Object.entries(agentMap).map(([category, agents]) => ({
|
|
508
|
+
category,
|
|
509
|
+
coordinator: agents.coordinator,
|
|
510
|
+
worker: agents.worker,
|
|
511
|
+
type: 'default',
|
|
512
|
+
})),
|
|
513
|
+
}, null, 2),
|
|
514
|
+
}],
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
//# sourceMappingURL=workflow.js.map
|