@contractspec/example.agent-console 0.0.0-canary-20260113170453
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/.turbo/turbo-build$colon$bundle.log +280 -0
- package/.turbo/turbo-build.log +281 -0
- package/CHANGELOG.md +368 -0
- package/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/agent/agent.entity.d.ts +55 -0
- package/dist/agent/agent.entity.d.ts.map +1 -0
- package/dist/agent/agent.entity.js +136 -0
- package/dist/agent/agent.entity.js.map +1 -0
- package/dist/agent/agent.enum.d.ts +18 -0
- package/dist/agent/agent.enum.d.ts.map +1 -0
- package/dist/agent/agent.enum.js +34 -0
- package/dist/agent/agent.enum.js.map +1 -0
- package/dist/agent/agent.event.d.ts +128 -0
- package/dist/agent/agent.event.d.ts.map +1 -0
- package/dist/agent/agent.event.js +210 -0
- package/dist/agent/agent.event.js.map +1 -0
- package/dist/agent/agent.handler.d.ts +100 -0
- package/dist/agent/agent.handler.d.ts.map +1 -0
- package/dist/agent/agent.handler.js +84 -0
- package/dist/agent/agent.handler.js.map +1 -0
- package/dist/agent/agent.operation.d.ts +471 -0
- package/dist/agent/agent.operation.d.ts.map +1 -0
- package/dist/agent/agent.operation.js +486 -0
- package/dist/agent/agent.operation.js.map +1 -0
- package/dist/agent/agent.presentation.d.ts +18 -0
- package/dist/agent/agent.presentation.d.ts.map +1 -0
- package/dist/agent/agent.presentation.js +89 -0
- package/dist/agent/agent.presentation.js.map +1 -0
- package/dist/agent/agent.schema.d.ts +401 -0
- package/dist/agent/agent.schema.d.ts.map +1 -0
- package/dist/agent/agent.schema.js +406 -0
- package/dist/agent/agent.schema.js.map +1 -0
- package/dist/agent/agent.test-spec.d.ts +8 -0
- package/dist/agent/agent.test-spec.d.ts.map +1 -0
- package/dist/agent/agent.test-spec.js +65 -0
- package/dist/agent/agent.test-spec.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.js +9 -0
- package/dist/agent.capability.d.ts +7 -0
- package/dist/agent.capability.d.ts.map +1 -0
- package/dist/agent.capability.js +20 -0
- package/dist/agent.capability.js.map +1 -0
- package/dist/agent.feature.d.ts +12 -0
- package/dist/agent.feature.d.ts.map +1 -0
- package/dist/agent.feature.js +305 -0
- package/dist/agent.feature.js.map +1 -0
- package/dist/docs/agent-console.docblock.d.ts +1 -0
- package/dist/docs/agent-console.docblock.js +113 -0
- package/dist/docs/agent-console.docblock.js.map +1 -0
- package/dist/docs/index.d.ts +1 -0
- package/dist/docs/index.js +1 -0
- package/dist/example.d.ts +7 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +58 -0
- package/dist/example.js.map +1 -0
- package/dist/handlers/agent.handlers.d.ts +135 -0
- package/dist/handlers/agent.handlers.d.ts.map +1 -0
- package/dist/handlers/agent.handlers.js +263 -0
- package/dist/handlers/agent.handlers.js.map +1 -0
- package/dist/handlers/index.d.ts +5 -0
- package/dist/handlers/index.js +6 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +50 -0
- package/dist/presentations/index.d.ts +4 -0
- package/dist/presentations/index.js +5 -0
- package/dist/run/index.d.ts +8 -0
- package/dist/run/index.js +9 -0
- package/dist/run/run.entity.d.ts +82 -0
- package/dist/run/run.entity.d.ts.map +1 -0
- package/dist/run/run.entity.js +205 -0
- package/dist/run/run.entity.js.map +1 -0
- package/dist/run/run.enum.d.ts +22 -0
- package/dist/run/run.enum.d.ts.map +1 -0
- package/dist/run/run.enum.js +45 -0
- package/dist/run/run.enum.js.map +1 -0
- package/dist/run/run.event.d.ts +290 -0
- package/dist/run/run.event.d.ts.map +1 -0
- package/dist/run/run.event.js +434 -0
- package/dist/run/run.event.js.map +1 -0
- package/dist/run/run.handler.d.ts +203 -0
- package/dist/run/run.handler.d.ts.map +1 -0
- package/dist/run/run.handler.js +83 -0
- package/dist/run/run.handler.js.map +1 -0
- package/dist/run/run.operation.d.ts +720 -0
- package/dist/run/run.operation.d.ts.map +1 -0
- package/dist/run/run.operation.js +626 -0
- package/dist/run/run.operation.js.map +1 -0
- package/dist/run/run.presentation.d.ts +14 -0
- package/dist/run/run.presentation.d.ts.map +1 -0
- package/dist/run/run.presentation.js +65 -0
- package/dist/run/run.presentation.js.map +1 -0
- package/dist/run/run.schema.d.ts +416 -0
- package/dist/run/run.schema.d.ts.map +1 -0
- package/dist/run/run.schema.js +338 -0
- package/dist/run/run.schema.js.map +1 -0
- package/dist/run/run.test-spec.d.ts +8 -0
- package/dist/run/run.test-spec.d.ts.map +1 -0
- package/dist/run/run.test-spec.js +65 -0
- package/dist/run/run.test-spec.js.map +1 -0
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +20 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.js +5 -0
- package/dist/shared/mock-agents.d.ts +88 -0
- package/dist/shared/mock-agents.d.ts.map +1 -0
- package/dist/shared/mock-agents.js +94 -0
- package/dist/shared/mock-agents.js.map +1 -0
- package/dist/shared/mock-runs.d.ts +120 -0
- package/dist/shared/mock-runs.d.ts.map +1 -0
- package/dist/shared/mock-runs.js +118 -0
- package/dist/shared/mock-runs.js.map +1 -0
- package/dist/shared/mock-tools.d.ts +244 -0
- package/dist/shared/mock-tools.d.ts.map +1 -0
- package/dist/shared/mock-tools.js +181 -0
- package/dist/shared/mock-tools.js.map +1 -0
- package/dist/shared/overlay-types.d.ts +34 -0
- package/dist/shared/overlay-types.d.ts.map +1 -0
- package/dist/shared/overlay-types.js +0 -0
- package/dist/tool/index.d.ts +8 -0
- package/dist/tool/index.js +9 -0
- package/dist/tool/tool.entity.d.ts +42 -0
- package/dist/tool/tool.entity.d.ts.map +1 -0
- package/dist/tool/tool.entity.js +105 -0
- package/dist/tool/tool.entity.js.map +1 -0
- package/dist/tool/tool.enum.d.ts +18 -0
- package/dist/tool/tool.enum.d.ts.map +1 -0
- package/dist/tool/tool.enum.js +35 -0
- package/dist/tool/tool.enum.js.map +1 -0
- package/dist/tool/tool.event.d.ts +103 -0
- package/dist/tool/tool.event.d.ts.map +1 -0
- package/dist/tool/tool.event.js +159 -0
- package/dist/tool/tool.event.js.map +1 -0
- package/dist/tool/tool.handler.d.ts +315 -0
- package/dist/tool/tool.handler.d.ts.map +1 -0
- package/dist/tool/tool.handler.js +87 -0
- package/dist/tool/tool.handler.js.map +1 -0
- package/dist/tool/tool.operation.d.ts +411 -0
- package/dist/tool/tool.operation.d.ts.map +1 -0
- package/dist/tool/tool.operation.js +406 -0
- package/dist/tool/tool.operation.js.map +1 -0
- package/dist/tool/tool.presentation.d.ts +14 -0
- package/dist/tool/tool.presentation.d.ts.map +1 -0
- package/dist/tool/tool.presentation.js +65 -0
- package/dist/tool/tool.presentation.js.map +1 -0
- package/dist/tool/tool.schema.d.ts +218 -0
- package/dist/tool/tool.schema.d.ts.map +1 -0
- package/dist/tool/tool.schema.js +236 -0
- package/dist/tool/tool.schema.js.map +1 -0
- package/dist/tool/tool.test-spec.d.ts +8 -0
- package/dist/tool/tool.test-spec.d.ts.map +1 -0
- package/dist/tool/tool.test-spec.js +65 -0
- package/dist/tool/tool.test-spec.js.map +1 -0
- package/dist/ui/AgentDashboard.d.ts +7 -0
- package/dist/ui/AgentDashboard.d.ts.map +1 -0
- package/dist/ui/AgentDashboard.js +420 -0
- package/dist/ui/AgentDashboard.js.map +1 -0
- package/dist/ui/AgentRunList.d.ts +2 -0
- package/dist/ui/AgentRunList.js +5 -0
- package/dist/ui/AgentToolRegistry.d.ts +2 -0
- package/dist/ui/AgentToolRegistry.js +5 -0
- package/dist/ui/hooks/index.d.ts +6 -0
- package/dist/ui/hooks/index.js +8 -0
- package/dist/ui/hooks/useAgentList.d.ts +28 -0
- package/dist/ui/hooks/useAgentList.d.ts.map +1 -0
- package/dist/ui/hooks/useAgentList.js +66 -0
- package/dist/ui/hooks/useAgentList.js.map +1 -0
- package/dist/ui/hooks/useAgentMutations.d.ts +29 -0
- package/dist/ui/hooks/useAgentMutations.d.ts.map +1 -0
- package/dist/ui/hooks/useAgentMutations.js +124 -0
- package/dist/ui/hooks/useAgentMutations.js.map +1 -0
- package/dist/ui/hooks/useRunList.d.ts +24 -0
- package/dist/ui/hooks/useRunList.d.ts.map +1 -0
- package/dist/ui/hooks/useRunList.js +66 -0
- package/dist/ui/hooks/useRunList.js.map +1 -0
- package/dist/ui/hooks/useToolList.d.ts +40 -0
- package/dist/ui/hooks/useToolList.d.ts.map +1 -0
- package/dist/ui/hooks/useToolList.js +96 -0
- package/dist/ui/hooks/useToolList.js.map +1 -0
- package/dist/ui/index.d.ts +24 -0
- package/dist/ui/index.js +24 -0
- package/dist/ui/modals/AgentActionsModal.d.ts +27 -0
- package/dist/ui/modals/AgentActionsModal.d.ts.map +1 -0
- package/dist/ui/modals/AgentActionsModal.js +262 -0
- package/dist/ui/modals/AgentActionsModal.js.map +1 -0
- package/dist/ui/modals/CreateAgentModal.d.ts +25 -0
- package/dist/ui/modals/CreateAgentModal.d.ts.map +1 -0
- package/dist/ui/modals/CreateAgentModal.js +214 -0
- package/dist/ui/modals/CreateAgentModal.js.map +1 -0
- package/dist/ui/modals/index.d.ts +3 -0
- package/dist/ui/modals/index.js +4 -0
- package/dist/ui/overlays/demo-overlays.d.ts +19 -0
- package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
- package/dist/ui/overlays/demo-overlays.js +73 -0
- package/dist/ui/overlays/demo-overlays.js.map +1 -0
- package/dist/ui/overlays/index.d.ts +2 -0
- package/dist/ui/overlays/index.js +3 -0
- package/dist/ui/renderers/agent-list.markdown.d.ts +15 -0
- package/dist/ui/renderers/agent-list.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/agent-list.markdown.js +51 -0
- package/dist/ui/renderers/agent-list.markdown.js.map +1 -0
- package/dist/ui/renderers/agent-list.renderer.d.ts +11 -0
- package/dist/ui/renderers/agent-list.renderer.d.ts.map +1 -0
- package/dist/ui/renderers/agent-list.renderer.js +19 -0
- package/dist/ui/renderers/agent-list.renderer.js.map +1 -0
- package/dist/ui/renderers/dashboard.markdown.d.ts +15 -0
- package/dist/ui/renderers/dashboard.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/dashboard.markdown.js +100 -0
- package/dist/ui/renderers/dashboard.markdown.js.map +1 -0
- package/dist/ui/renderers/index.d.ts +6 -0
- package/dist/ui/renderers/index.js +7 -0
- package/dist/ui/renderers/run-list.markdown.d.ts +15 -0
- package/dist/ui/renderers/run-list.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/run-list.markdown.js +44 -0
- package/dist/ui/renderers/run-list.markdown.js.map +1 -0
- package/dist/ui/renderers/tool-registry.markdown.d.ts +15 -0
- package/dist/ui/renderers/tool-registry.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/tool-registry.markdown.js +55 -0
- package/dist/ui/renderers/tool-registry.markdown.js.map +1 -0
- package/dist/ui/views/AgentListView.d.ts +7 -0
- package/dist/ui/views/AgentListView.d.ts.map +1 -0
- package/dist/ui/views/AgentListView.js +93 -0
- package/dist/ui/views/AgentListView.js.map +1 -0
- package/dist/ui/views/RunListView.d.ts +14 -0
- package/dist/ui/views/RunListView.d.ts.map +1 -0
- package/dist/ui/views/RunListView.js +165 -0
- package/dist/ui/views/RunListView.js.map +1 -0
- package/dist/ui/views/ToolRegistryView.d.ts +14 -0
- package/dist/ui/views/ToolRegistryView.d.ts.map +1 -0
- package/dist/ui/views/ToolRegistryView.js +97 -0
- package/dist/ui/views/ToolRegistryView.js.map +1 -0
- package/dist/ui/views/index.d.ts +4 -0
- package/dist/ui/views/index.js +5 -0
- package/example.ts +1 -0
- package/package.json +155 -0
- package/src/agent/agent.entity.ts +137 -0
- package/src/agent/agent.enum.ts +31 -0
- package/src/agent/agent.event.ts +142 -0
- package/src/agent/agent.handler.ts +178 -0
- package/src/agent/agent.operation.ts +444 -0
- package/src/agent/agent.presentation.ts +80 -0
- package/src/agent/agent.schema.ts +214 -0
- package/src/agent/agent.test-spec.ts +55 -0
- package/src/agent/index.ts +67 -0
- package/src/agent.capability.ts +13 -0
- package/src/agent.feature.ts +147 -0
- package/src/docs/agent-console.docblock.ts +97 -0
- package/src/docs/index.ts +1 -0
- package/src/example.ts +41 -0
- package/src/handlers/agent.handlers.ts +572 -0
- package/src/handlers/index.ts +30 -0
- package/src/index.ts +32 -0
- package/src/presentations/index.ts +26 -0
- package/src/run/index.ts +68 -0
- package/src/run/run.entity.ts +175 -0
- package/src/run/run.enum.ts +43 -0
- package/src/run/run.event.ts +264 -0
- package/src/run/run.handler.ts +138 -0
- package/src/run/run.operation.ts +524 -0
- package/src/run/run.presentation.ts +54 -0
- package/src/run/run.schema.ts +169 -0
- package/src/run/run.test-spec.ts +55 -0
- package/src/seeders/index.ts +29 -0
- package/src/shared/index.ts +6 -0
- package/src/shared/mock-agents.ts +81 -0
- package/src/shared/mock-runs.ts +107 -0
- package/src/shared/mock-tools.ts +145 -0
- package/src/shared/overlay-types.ts +39 -0
- package/src/tool/index.ts +60 -0
- package/src/tool/tool.entity.ts +99 -0
- package/src/tool/tool.enum.ts +32 -0
- package/src/tool/tool.event.ts +119 -0
- package/src/tool/tool.handler.ts +154 -0
- package/src/tool/tool.operation.ts +366 -0
- package/src/tool/tool.presentation.ts +55 -0
- package/src/tool/tool.schema.ts +133 -0
- package/src/tool/tool.test-spec.ts +55 -0
- package/src/ui/AgentDashboard.tsx +416 -0
- package/src/ui/AgentRunList.tsx +8 -0
- package/src/ui/AgentToolRegistry.tsx +8 -0
- package/src/ui/hooks/index.ts +14 -0
- package/src/ui/hooks/useAgentList.ts +80 -0
- package/src/ui/hooks/useAgentMutations.ts +156 -0
- package/src/ui/hooks/useRunList.ts +81 -0
- package/src/ui/hooks/useToolList.ts +122 -0
- package/src/ui/index.ts +21 -0
- package/src/ui/modals/AgentActionsModal.tsx +306 -0
- package/src/ui/modals/CreateAgentModal.tsx +257 -0
- package/src/ui/modals/index.ts +2 -0
- package/src/ui/overlays/demo-overlays.ts +77 -0
- package/src/ui/overlays/index.ts +1 -0
- package/src/ui/renderers/agent-list.markdown.ts +84 -0
- package/src/ui/renderers/agent-list.renderer.tsx +27 -0
- package/src/ui/renderers/dashboard.markdown.ts +169 -0
- package/src/ui/renderers/index.ts +12 -0
- package/src/ui/renderers/run-list.markdown.ts +75 -0
- package/src/ui/renderers/tool-registry.markdown.ts +91 -0
- package/src/ui/views/AgentListView.tsx +113 -0
- package/src/ui/views/RunListView.tsx +173 -0
- package/src/ui/views/ToolRegistryView.tsx +140 -0
- package/src/ui/views/index.ts +6 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.js +7 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime-local Agent Console handlers
|
|
3
|
+
*
|
|
4
|
+
* Database-backed handlers for agent management and runs.
|
|
5
|
+
*/
|
|
6
|
+
import type { DatabasePort } from '@contractspec/lib.runtime-sandbox';
|
|
7
|
+
import { web } from '@contractspec/lib.runtime-sandbox';
|
|
8
|
+
const { generateId } = web;
|
|
9
|
+
|
|
10
|
+
// ============ Types ============
|
|
11
|
+
|
|
12
|
+
export interface Agent {
|
|
13
|
+
id: string;
|
|
14
|
+
projectId: string;
|
|
15
|
+
organizationId: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
modelProvider: string;
|
|
19
|
+
modelName: string;
|
|
20
|
+
systemPrompt?: string;
|
|
21
|
+
temperature: number;
|
|
22
|
+
maxTokens: number;
|
|
23
|
+
status: 'DRAFT' | 'ACTIVE' | 'PAUSED' | 'ARCHIVED';
|
|
24
|
+
createdAt: Date;
|
|
25
|
+
updatedAt: Date;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Tool {
|
|
29
|
+
id: string;
|
|
30
|
+
projectId: string;
|
|
31
|
+
organizationId: string;
|
|
32
|
+
name: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
version: string;
|
|
35
|
+
category:
|
|
36
|
+
| 'RETRIEVAL'
|
|
37
|
+
| 'COMPUTATION'
|
|
38
|
+
| 'COMMUNICATION'
|
|
39
|
+
| 'INTEGRATION'
|
|
40
|
+
| 'UTILITY'
|
|
41
|
+
| 'CUSTOM';
|
|
42
|
+
status: 'ACTIVE' | 'DISABLED' | 'DEPRECATED' | 'DRAFT';
|
|
43
|
+
inputSchema?: string;
|
|
44
|
+
outputSchema?: string;
|
|
45
|
+
endpoint?: string;
|
|
46
|
+
createdAt: Date;
|
|
47
|
+
updatedAt: Date;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Run {
|
|
51
|
+
id: string;
|
|
52
|
+
projectId: string;
|
|
53
|
+
agentId: string;
|
|
54
|
+
agentName?: string;
|
|
55
|
+
status: 'QUEUED' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';
|
|
56
|
+
input?: string;
|
|
57
|
+
output?: string;
|
|
58
|
+
totalTokens: number;
|
|
59
|
+
promptTokens: number;
|
|
60
|
+
completionTokens: number;
|
|
61
|
+
estimatedCostUsd: number;
|
|
62
|
+
durationMs?: number;
|
|
63
|
+
errorMessage?: string;
|
|
64
|
+
queuedAt: Date;
|
|
65
|
+
startedAt?: Date;
|
|
66
|
+
completedAt?: Date;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface RunMetrics {
|
|
70
|
+
totalRuns: number;
|
|
71
|
+
successRate: number;
|
|
72
|
+
averageDurationMs: number;
|
|
73
|
+
totalTokens: number;
|
|
74
|
+
totalCostUsd: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ListAgentsInput {
|
|
78
|
+
projectId: string;
|
|
79
|
+
organizationId?: string;
|
|
80
|
+
status?: Agent['status'] | 'all';
|
|
81
|
+
search?: string;
|
|
82
|
+
limit?: number;
|
|
83
|
+
offset?: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface ListAgentsOutput {
|
|
87
|
+
items: Agent[];
|
|
88
|
+
total: number;
|
|
89
|
+
hasMore: boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface ListToolsInput {
|
|
93
|
+
projectId: string;
|
|
94
|
+
organizationId?: string;
|
|
95
|
+
category?: Tool['category'] | 'all';
|
|
96
|
+
status?: Tool['status'] | 'all';
|
|
97
|
+
search?: string;
|
|
98
|
+
limit?: number;
|
|
99
|
+
offset?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ListToolsOutput {
|
|
103
|
+
items: Tool[];
|
|
104
|
+
total: number;
|
|
105
|
+
hasMore: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ListRunsInput {
|
|
109
|
+
projectId: string;
|
|
110
|
+
organizationId?: string;
|
|
111
|
+
agentId?: string;
|
|
112
|
+
status?: Run['status'] | 'all';
|
|
113
|
+
limit?: number;
|
|
114
|
+
offset?: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ListRunsOutput {
|
|
118
|
+
items: Run[];
|
|
119
|
+
total: number;
|
|
120
|
+
hasMore: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface CreateAgentInput {
|
|
124
|
+
name: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
modelProvider?: string;
|
|
127
|
+
modelName?: string;
|
|
128
|
+
systemPrompt?: string;
|
|
129
|
+
temperature?: number;
|
|
130
|
+
maxTokens?: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface UpdateAgentInput {
|
|
134
|
+
id: string;
|
|
135
|
+
name?: string;
|
|
136
|
+
description?: string;
|
|
137
|
+
status?: Agent['status'];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ============ Row Types ============
|
|
141
|
+
|
|
142
|
+
interface AgentRow extends Record<string, unknown> {
|
|
143
|
+
id: string;
|
|
144
|
+
projectId: string;
|
|
145
|
+
organizationId: string;
|
|
146
|
+
name: string;
|
|
147
|
+
description: string | null;
|
|
148
|
+
modelProvider: string;
|
|
149
|
+
modelName: string;
|
|
150
|
+
systemPrompt: string | null;
|
|
151
|
+
temperature: number;
|
|
152
|
+
maxTokens: number;
|
|
153
|
+
status: string;
|
|
154
|
+
createdAt: string;
|
|
155
|
+
updatedAt: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface ToolRow extends Record<string, unknown> {
|
|
159
|
+
id: string;
|
|
160
|
+
projectId: string;
|
|
161
|
+
organizationId: string;
|
|
162
|
+
name: string;
|
|
163
|
+
description: string | null;
|
|
164
|
+
version: string;
|
|
165
|
+
category: string;
|
|
166
|
+
status: string;
|
|
167
|
+
inputSchema: string | null;
|
|
168
|
+
outputSchema: string | null;
|
|
169
|
+
endpoint: string | null;
|
|
170
|
+
createdAt: string;
|
|
171
|
+
updatedAt: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
interface RunRow extends Record<string, unknown> {
|
|
175
|
+
id: string;
|
|
176
|
+
projectId: string;
|
|
177
|
+
agentId: string;
|
|
178
|
+
status: string;
|
|
179
|
+
input: string | null;
|
|
180
|
+
output: string | null;
|
|
181
|
+
totalTokens: number;
|
|
182
|
+
promptTokens: number;
|
|
183
|
+
completionTokens: number;
|
|
184
|
+
estimatedCostUsd: number;
|
|
185
|
+
durationMs: number | null;
|
|
186
|
+
errorMessage: string | null;
|
|
187
|
+
queuedAt: string;
|
|
188
|
+
startedAt: string | null;
|
|
189
|
+
completedAt: string | null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function rowToAgent(row: AgentRow): Agent {
|
|
193
|
+
return {
|
|
194
|
+
id: row.id,
|
|
195
|
+
projectId: row.projectId,
|
|
196
|
+
organizationId: row.organizationId,
|
|
197
|
+
name: row.name,
|
|
198
|
+
description: row.description ?? undefined,
|
|
199
|
+
modelProvider: row.modelProvider,
|
|
200
|
+
modelName: row.modelName,
|
|
201
|
+
systemPrompt: row.systemPrompt ?? undefined,
|
|
202
|
+
temperature: row.temperature,
|
|
203
|
+
maxTokens: row.maxTokens,
|
|
204
|
+
status: row.status as Agent['status'],
|
|
205
|
+
createdAt: new Date(row.createdAt),
|
|
206
|
+
updatedAt: new Date(row.updatedAt),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function rowToTool(row: ToolRow): Tool {
|
|
211
|
+
return {
|
|
212
|
+
id: row.id,
|
|
213
|
+
projectId: row.projectId,
|
|
214
|
+
organizationId: row.organizationId,
|
|
215
|
+
name: row.name,
|
|
216
|
+
description: row.description ?? undefined,
|
|
217
|
+
version: row.version,
|
|
218
|
+
category: row.category as Tool['category'],
|
|
219
|
+
status: row.status as Tool['status'],
|
|
220
|
+
inputSchema: row.inputSchema ?? undefined,
|
|
221
|
+
outputSchema: row.outputSchema ?? undefined,
|
|
222
|
+
endpoint: row.endpoint ?? undefined,
|
|
223
|
+
createdAt: new Date(row.createdAt),
|
|
224
|
+
updatedAt: new Date(row.updatedAt),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function rowToRun(row: RunRow, agentName?: string): Run {
|
|
229
|
+
return {
|
|
230
|
+
id: row.id,
|
|
231
|
+
projectId: row.projectId,
|
|
232
|
+
agentId: row.agentId,
|
|
233
|
+
agentName,
|
|
234
|
+
status: row.status as Run['status'],
|
|
235
|
+
input: row.input ?? undefined,
|
|
236
|
+
output: row.output ?? undefined,
|
|
237
|
+
totalTokens: row.totalTokens,
|
|
238
|
+
promptTokens: row.promptTokens,
|
|
239
|
+
completionTokens: row.completionTokens,
|
|
240
|
+
estimatedCostUsd: row.estimatedCostUsd,
|
|
241
|
+
durationMs: row.durationMs ?? undefined,
|
|
242
|
+
errorMessage: row.errorMessage ?? undefined,
|
|
243
|
+
queuedAt: new Date(row.queuedAt),
|
|
244
|
+
startedAt: row.startedAt ? new Date(row.startedAt) : undefined,
|
|
245
|
+
completedAt: row.completedAt ? new Date(row.completedAt) : undefined,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ============ Handler Factory ============
|
|
250
|
+
|
|
251
|
+
export function createAgentHandlers(db: DatabasePort) {
|
|
252
|
+
/**
|
|
253
|
+
* List agents
|
|
254
|
+
*/
|
|
255
|
+
async function listAgents(input: ListAgentsInput): Promise<ListAgentsOutput> {
|
|
256
|
+
const {
|
|
257
|
+
projectId,
|
|
258
|
+
organizationId,
|
|
259
|
+
status,
|
|
260
|
+
search,
|
|
261
|
+
limit = 20,
|
|
262
|
+
offset = 0,
|
|
263
|
+
} = input;
|
|
264
|
+
|
|
265
|
+
let whereClause = 'WHERE projectId = ?';
|
|
266
|
+
const params: (string | number)[] = [projectId];
|
|
267
|
+
|
|
268
|
+
if (organizationId) {
|
|
269
|
+
whereClause += ' AND organizationId = ?';
|
|
270
|
+
params.push(organizationId);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (status && status !== 'all') {
|
|
274
|
+
whereClause += ' AND status = ?';
|
|
275
|
+
params.push(status);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (search) {
|
|
279
|
+
whereClause += ' AND (name LIKE ? OR description LIKE ?)';
|
|
280
|
+
params.push(`%${search}%`, `%${search}%`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const countResult = (
|
|
284
|
+
await db.query(
|
|
285
|
+
`SELECT COUNT(*) as count FROM agent_definition ${whereClause}`,
|
|
286
|
+
params
|
|
287
|
+
)
|
|
288
|
+
).rows as unknown as { count: number }[];
|
|
289
|
+
const total = countResult[0]?.count ?? 0;
|
|
290
|
+
|
|
291
|
+
const rows = (
|
|
292
|
+
await db.query(
|
|
293
|
+
`SELECT * FROM agent_definition ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
294
|
+
[...params, limit, offset]
|
|
295
|
+
)
|
|
296
|
+
).rows as unknown as AgentRow[];
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
items: rows.map(rowToAgent),
|
|
300
|
+
total,
|
|
301
|
+
hasMore: offset + rows.length < total,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Get a single agent
|
|
307
|
+
*/
|
|
308
|
+
async function getAgent(id: string): Promise<Agent | null> {
|
|
309
|
+
const rows = (
|
|
310
|
+
await db.query(`SELECT * FROM agent_definition WHERE id = ?`, [id])
|
|
311
|
+
).rows as unknown as AgentRow[];
|
|
312
|
+
return rows[0] ? rowToAgent(rows[0]) : null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Create an agent
|
|
317
|
+
*/
|
|
318
|
+
async function createAgent(
|
|
319
|
+
input: CreateAgentInput,
|
|
320
|
+
context: { projectId: string; organizationId: string }
|
|
321
|
+
): Promise<Agent> {
|
|
322
|
+
const id = generateId('agent');
|
|
323
|
+
const now = new Date().toISOString();
|
|
324
|
+
|
|
325
|
+
await db.execute(
|
|
326
|
+
`INSERT INTO agent_definition (id, projectId, organizationId, name, description, modelProvider, modelName, systemPrompt, temperature, maxTokens, status, createdAt, updatedAt)
|
|
327
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
328
|
+
[
|
|
329
|
+
id,
|
|
330
|
+
context.projectId,
|
|
331
|
+
context.organizationId,
|
|
332
|
+
input.name,
|
|
333
|
+
input.description ?? null,
|
|
334
|
+
input.modelProvider ?? 'openai',
|
|
335
|
+
input.modelName ?? 'gpt-4',
|
|
336
|
+
input.systemPrompt ?? null,
|
|
337
|
+
input.temperature ?? 0.7,
|
|
338
|
+
input.maxTokens ?? 4096,
|
|
339
|
+
'DRAFT',
|
|
340
|
+
now,
|
|
341
|
+
now,
|
|
342
|
+
]
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const rows = (
|
|
346
|
+
await db.query(`SELECT * FROM agent_definition WHERE id = ?`, [id])
|
|
347
|
+
).rows as unknown as AgentRow[];
|
|
348
|
+
|
|
349
|
+
const row = rows[0];
|
|
350
|
+
if (!row) {
|
|
351
|
+
throw new Error('Failed to retrieve created agent');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return rowToAgent(row);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Update an agent
|
|
359
|
+
*/
|
|
360
|
+
async function updateAgent(input: UpdateAgentInput): Promise<Agent> {
|
|
361
|
+
const now = new Date().toISOString();
|
|
362
|
+
const updates: string[] = ['updatedAt = ?'];
|
|
363
|
+
const params: (string | null)[] = [now];
|
|
364
|
+
|
|
365
|
+
if (input.name !== undefined) {
|
|
366
|
+
updates.push('name = ?');
|
|
367
|
+
params.push(input.name);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (input.description !== undefined) {
|
|
371
|
+
updates.push('description = ?');
|
|
372
|
+
params.push(input.description);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (input.status !== undefined) {
|
|
376
|
+
updates.push('status = ?');
|
|
377
|
+
params.push(input.status);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
params.push(input.id);
|
|
381
|
+
|
|
382
|
+
await db.execute(
|
|
383
|
+
`UPDATE agent_definition SET ${updates.join(', ')} WHERE id = ?`,
|
|
384
|
+
params
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
const rows = (
|
|
388
|
+
await db.query(`SELECT * FROM agent_definition WHERE id = ?`, [input.id])
|
|
389
|
+
).rows as unknown as AgentRow[];
|
|
390
|
+
|
|
391
|
+
if (!rows[0]) {
|
|
392
|
+
throw new Error('NOT_FOUND');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return rowToAgent(rows[0]);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* List tools
|
|
400
|
+
*/
|
|
401
|
+
async function listTools(input: ListToolsInput): Promise<ListToolsOutput> {
|
|
402
|
+
const {
|
|
403
|
+
projectId,
|
|
404
|
+
organizationId,
|
|
405
|
+
category,
|
|
406
|
+
status,
|
|
407
|
+
search,
|
|
408
|
+
limit = 50,
|
|
409
|
+
offset = 0,
|
|
410
|
+
} = input;
|
|
411
|
+
|
|
412
|
+
let whereClause = 'WHERE projectId = ?';
|
|
413
|
+
const params: (string | number)[] = [projectId];
|
|
414
|
+
|
|
415
|
+
if (organizationId) {
|
|
416
|
+
whereClause += ' AND organizationId = ?';
|
|
417
|
+
params.push(organizationId);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (category && category !== 'all') {
|
|
421
|
+
whereClause += ' AND category = ?';
|
|
422
|
+
params.push(category);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (status && status !== 'all') {
|
|
426
|
+
whereClause += ' AND status = ?';
|
|
427
|
+
params.push(status);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (search) {
|
|
431
|
+
whereClause += ' AND (name LIKE ? OR description LIKE ?)';
|
|
432
|
+
params.push(`%${search}%`, `%${search}%`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const countResult = (
|
|
436
|
+
await db.query(
|
|
437
|
+
`SELECT COUNT(*) as count FROM agent_tool ${whereClause}`,
|
|
438
|
+
params
|
|
439
|
+
)
|
|
440
|
+
).rows as unknown as { count: number }[];
|
|
441
|
+
const total = countResult[0]?.count ?? 0;
|
|
442
|
+
|
|
443
|
+
const rows = (
|
|
444
|
+
await db.query(
|
|
445
|
+
`SELECT * FROM agent_tool ${whereClause} ORDER BY name ASC LIMIT ? OFFSET ?`,
|
|
446
|
+
[...params, limit, offset]
|
|
447
|
+
)
|
|
448
|
+
).rows as unknown as ToolRow[];
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
items: rows.map(rowToTool),
|
|
452
|
+
total,
|
|
453
|
+
hasMore: offset + rows.length < total,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* List runs
|
|
459
|
+
*/
|
|
460
|
+
async function listRuns(input: ListRunsInput): Promise<ListRunsOutput> {
|
|
461
|
+
const { projectId, agentId, status, limit = 20, offset = 0 } = input;
|
|
462
|
+
|
|
463
|
+
let whereClause = 'WHERE r.projectId = ?';
|
|
464
|
+
const params: (string | number)[] = [projectId];
|
|
465
|
+
|
|
466
|
+
if (agentId) {
|
|
467
|
+
whereClause += ' AND r.agentId = ?';
|
|
468
|
+
params.push(agentId);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (status && status !== 'all') {
|
|
472
|
+
whereClause += ' AND r.status = ?';
|
|
473
|
+
params.push(status);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const countResult = (
|
|
477
|
+
await db.query(
|
|
478
|
+
`SELECT COUNT(*) as count FROM agent_run r ${whereClause}`,
|
|
479
|
+
params
|
|
480
|
+
)
|
|
481
|
+
).rows as unknown as { count: number }[];
|
|
482
|
+
const total = countResult[0]?.count ?? 0;
|
|
483
|
+
|
|
484
|
+
const rows = (
|
|
485
|
+
await db.query(
|
|
486
|
+
`SELECT r.*, a.name as agentName
|
|
487
|
+
FROM agent_run r
|
|
488
|
+
LEFT JOIN agent_definition a ON r.agentId = a.id
|
|
489
|
+
${whereClause}
|
|
490
|
+
ORDER BY r.queuedAt DESC LIMIT ? OFFSET ?`,
|
|
491
|
+
[...params, limit, offset]
|
|
492
|
+
)
|
|
493
|
+
).rows as unknown as (RunRow & { agentName: string })[];
|
|
494
|
+
|
|
495
|
+
return {
|
|
496
|
+
items: rows.map((r) => rowToRun(r, r.agentName)),
|
|
497
|
+
total,
|
|
498
|
+
hasMore: offset + rows.length < total,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Get run metrics
|
|
504
|
+
*/
|
|
505
|
+
async function getRunMetrics(input: {
|
|
506
|
+
projectId: string;
|
|
507
|
+
agentId?: string;
|
|
508
|
+
startDate?: Date;
|
|
509
|
+
endDate?: Date;
|
|
510
|
+
}): Promise<RunMetrics> {
|
|
511
|
+
let whereClause = 'WHERE projectId = ?';
|
|
512
|
+
const params: (string | number)[] = [input.projectId];
|
|
513
|
+
|
|
514
|
+
if (input.agentId) {
|
|
515
|
+
whereClause += ' AND agentId = ?';
|
|
516
|
+
params.push(input.agentId);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (input.startDate) {
|
|
520
|
+
whereClause += ' AND queuedAt >= ?';
|
|
521
|
+
params.push(input.startDate.toISOString());
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (input.endDate) {
|
|
525
|
+
whereClause += ' AND queuedAt <= ?';
|
|
526
|
+
params.push(input.endDate.toISOString());
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const result = (
|
|
530
|
+
await db.query(
|
|
531
|
+
`SELECT
|
|
532
|
+
COUNT(*) as totalRuns,
|
|
533
|
+
SUM(CASE WHEN status = 'COMPLETED' THEN 1 ELSE 0 END) as completedRuns,
|
|
534
|
+
AVG(CASE WHEN status = 'COMPLETED' THEN durationMs ELSE NULL END) as avgDuration,
|
|
535
|
+
COALESCE(SUM(totalTokens), 0) as totalTokens,
|
|
536
|
+
COALESCE(SUM(estimatedCostUsd), 0) as totalCost
|
|
537
|
+
FROM agent_run ${whereClause}`,
|
|
538
|
+
params
|
|
539
|
+
)
|
|
540
|
+
).rows as unknown as {
|
|
541
|
+
totalRuns: number;
|
|
542
|
+
completedRuns: number;
|
|
543
|
+
avgDuration: number | null;
|
|
544
|
+
totalTokens: number;
|
|
545
|
+
totalCost: number;
|
|
546
|
+
}[];
|
|
547
|
+
|
|
548
|
+
const data = result[0];
|
|
549
|
+
const totalRuns = data?.totalRuns ?? 0;
|
|
550
|
+
const completedRuns = data?.completedRuns ?? 0;
|
|
551
|
+
|
|
552
|
+
return {
|
|
553
|
+
totalRuns,
|
|
554
|
+
successRate: totalRuns > 0 ? completedRuns / totalRuns : 0,
|
|
555
|
+
averageDurationMs: data?.avgDuration ?? 0,
|
|
556
|
+
totalTokens: data?.totalTokens ?? 0,
|
|
557
|
+
totalCostUsd: data?.totalCost ?? 0,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
listAgents,
|
|
563
|
+
getAgent,
|
|
564
|
+
createAgent,
|
|
565
|
+
updateAgent,
|
|
566
|
+
listTools,
|
|
567
|
+
listRuns,
|
|
568
|
+
getRunMetrics,
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export type AgentHandlers = ReturnType<typeof createAgentHandlers>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Console Handlers - re-exports from domain modules for backward compatibility.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Agent handlers and types
|
|
6
|
+
export {
|
|
7
|
+
mockCreateAgentHandler,
|
|
8
|
+
mockGetAgentHandler,
|
|
9
|
+
mockListAgentsHandler,
|
|
10
|
+
type AgentSummary,
|
|
11
|
+
} from '../agent/agent.handler';
|
|
12
|
+
|
|
13
|
+
// Run handlers and types
|
|
14
|
+
export {
|
|
15
|
+
mockExecuteAgentHandler,
|
|
16
|
+
mockGetRunHandler,
|
|
17
|
+
mockListRunsHandler,
|
|
18
|
+
type RunSummary,
|
|
19
|
+
} from '../run/run.handler';
|
|
20
|
+
|
|
21
|
+
// Tool handlers and types
|
|
22
|
+
export {
|
|
23
|
+
mockCreateToolHandler,
|
|
24
|
+
mockGetToolHandler,
|
|
25
|
+
mockListToolsHandler,
|
|
26
|
+
type ToolSummary,
|
|
27
|
+
} from '../tool/tool.handler';
|
|
28
|
+
|
|
29
|
+
// Runtime handlers (PGLite)
|
|
30
|
+
export * from './agent.handlers';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Console Example
|
|
3
|
+
*
|
|
4
|
+
* A ContractSpec example demonstrating AI agent orchestration with tools, runs, and logs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import {
|
|
9
|
+
* ToolEntity,
|
|
10
|
+
* AgentEntity,
|
|
11
|
+
* RunEntity,
|
|
12
|
+
* CreateToolCommand,
|
|
13
|
+
* ExecuteAgentCommand
|
|
14
|
+
* } from '@contractspec/example.agent-console';
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Domain exports
|
|
19
|
+
export * from './agent';
|
|
20
|
+
export * from './run';
|
|
21
|
+
export * from './tool';
|
|
22
|
+
export * from './shared';
|
|
23
|
+
export * from './ui';
|
|
24
|
+
export {
|
|
25
|
+
createAgentHandlers,
|
|
26
|
+
type AgentHandlers,
|
|
27
|
+
} from './handlers/agent.handlers';
|
|
28
|
+
|
|
29
|
+
// Feature spec export
|
|
30
|
+
export * from './agent.feature';
|
|
31
|
+
export { default as example } from './example';
|
|
32
|
+
import './docs';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Console Presentations - re-exports from domain modules for backward compatibility.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Agent presentations
|
|
6
|
+
export {
|
|
7
|
+
AgentListPresentation,
|
|
8
|
+
AgentDetailPresentation,
|
|
9
|
+
AgentConsoleDashboardPresentation,
|
|
10
|
+
} from '../agent/agent.presentation';
|
|
11
|
+
|
|
12
|
+
// Run presentations
|
|
13
|
+
export {
|
|
14
|
+
RunListPresentation,
|
|
15
|
+
RunDetailPresentation,
|
|
16
|
+
} from '../run/run.presentation';
|
|
17
|
+
// Alias: RunMetricsPresentation -> RunDetailPresentation (for backward compatibility)
|
|
18
|
+
export { RunDetailPresentation as RunMetricsPresentation } from '../run/run.presentation';
|
|
19
|
+
|
|
20
|
+
// Tool presentations
|
|
21
|
+
export {
|
|
22
|
+
ToolListPresentation,
|
|
23
|
+
ToolDetailPresentation,
|
|
24
|
+
} from '../tool/tool.presentation';
|
|
25
|
+
// Alias: ToolRegistryPresentation -> ToolListPresentation (for backward compatibility)
|
|
26
|
+
export { ToolListPresentation as ToolRegistryPresentation } from '../tool/tool.presentation';
|