elasticdash-test 0.1.25-alpha-2 → 0.1.26-alpha-1
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/docs/agent-integration-guide.md +228 -190
- package/package.json +1 -1
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
> **When to use**: Follow this guide step-by-step when a user asks you to "integrate ElasticDash", "set up ElasticDash testing", "implement elasticdash-test", or similar. Each step produces a specific file — work through them in order.
|
|
6
6
|
>
|
|
7
7
|
> **How to use**: Read the full guide first to understand the project's structure, then execute each step. Use the decision trees section to choose the right pattern for the user's project (framework type, module system, tool architecture).
|
|
8
|
+
>
|
|
9
|
+
> **Important**: Do NOT leave `YOUR_TOOL_NAME` / `YOUR_WORKFLOW_NAME` placeholders in generated files. Before creating `ed_tools.ts` and `ed_workflows.ts`, scan the user's codebase to identify their actual tool functions (functions that call external APIs, databases, or services) and workflow functions (async functions that orchestrate LLM calls and tool calls). Create the files with the real function names, imports, and types found in the codebase. If no tools or workflows exist yet, ask the user which functions to instrument rather than generating placeholder files.
|
|
10
|
+
>
|
|
11
|
+
> **Automation level**: Automatically implement all steps unless you are not confident about a specific change (e.g., unclear which function is a tool vs. a utility, or ambiguous workflow boundaries). In those cases, ask the user before proceeding. For straightforward tool/workflow functions, proceed without asking.
|
|
8
12
|
|
|
9
13
|
---
|
|
10
14
|
|
|
@@ -12,9 +16,18 @@
|
|
|
12
16
|
|
|
13
17
|
- Node.js >= 20
|
|
14
18
|
- npm, yarn, or pnpm
|
|
15
|
-
- At least one AI workflow function (a callable async function that makes LLM/tool calls)
|
|
16
19
|
- LLM provider API keys for providers used in workflows (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`)
|
|
17
20
|
|
|
21
|
+
### Identify tools and workflows in the codebase
|
|
22
|
+
|
|
23
|
+
Before starting, scan the project to find:
|
|
24
|
+
|
|
25
|
+
- **Tool functions**: Exported async functions that call external services (APIs, databases, search, etc.). Look for functions that use `fetch`, database clients, SDK calls, or any external I/O. These go in `ed_tools.ts`.
|
|
26
|
+
- **Workflow functions**: Exported async functions that orchestrate an AI pipeline — typically calling an LLM and one or more tools. Look for functions that call OpenAI, Anthropic, Gemini, or similar SDKs. These go in `ed_workflows.ts`.
|
|
27
|
+
|
|
28
|
+
If the project has no clear tool or workflow functions yet, ask the user:
|
|
29
|
+
> "Which functions in your codebase make external API/service calls (tools), and which functions orchestrate your AI workflow? I need to know so I can set up ElasticDash instrumentation."
|
|
30
|
+
|
|
18
31
|
### Detect project type before starting
|
|
19
32
|
|
|
20
33
|
Check these before choosing patterns:
|
|
@@ -28,6 +41,26 @@ Check these before choosing patterns:
|
|
|
28
41
|
|
|
29
42
|
---
|
|
30
43
|
|
|
44
|
+
## Step 0: Check environment variables (do this FIRST)
|
|
45
|
+
|
|
46
|
+
Before making any code changes, check the project's `.env` file for the required ElasticDash variables.
|
|
47
|
+
|
|
48
|
+
### 1. Check for `ELASTICDASH_API_URL`
|
|
49
|
+
|
|
50
|
+
- If present: use the existing value.
|
|
51
|
+
- If missing: add `ELASTICDASH_API_URL=https://server.elasticdash.com` to `.env`.
|
|
52
|
+
|
|
53
|
+
### 2. Check for `ELASTICDASH_API_KEY`
|
|
54
|
+
|
|
55
|
+
- If present: proceed to Step 1.
|
|
56
|
+
- If missing: **STOP and ask the user**:
|
|
57
|
+
|
|
58
|
+
> "Your project needs an ElasticDash API key. Please complete the onboarding at https://app.elasticdash.com to get your project API key, then add `ELASTICDASH_API_KEY=ed_your_key_here` to your `.env` file. Let me know when it's ready."
|
|
59
|
+
|
|
60
|
+
**Do not continue until `ELASTICDASH_API_KEY` is set.** The SDK cannot connect to the backend without it.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
31
64
|
## Step 1: Install
|
|
32
65
|
|
|
33
66
|
```bash
|
|
@@ -45,161 +78,63 @@ Add to `.gitignore`:
|
|
|
45
78
|
|
|
46
79
|
## Step 2: Create `ed_tools.ts`
|
|
47
80
|
|
|
48
|
-
Create `ed_tools.ts` in the project root. This file wraps each tool function with
|
|
81
|
+
Create `ed_tools.ts` in the project root. This file wraps each tool function with `wrapTool()` for automatic tracing, mocking, and telemetry.
|
|
49
82
|
|
|
50
|
-
|
|
83
|
+
**Before writing this file**: Search the codebase for functions that call external services (APIs, databases, SDKs). Each one becomes a wrapped export in `ed_tools.ts`. Replace all `YOUR_TOOL_*` and `YOUR_SOURCE_PATH_*` placeholders below with the actual function names and import paths found in the project.
|
|
51
84
|
|
|
52
|
-
|
|
53
|
-
- **Pattern A**: `withTrace` HOF with central dispatcher. Use when tools are pure functions called through a single `dispatchTool(name, args)` dispatcher.
|
|
54
|
-
|
|
55
|
-
### Pattern B template (recommended)
|
|
85
|
+
### Template
|
|
56
86
|
|
|
57
87
|
```ts
|
|
58
88
|
// ed_tools.ts
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
89
|
+
import { setElasticDashModule } from './ed_workflows'
|
|
90
|
+
|
|
91
|
+
// Import original tool implementations from the actual source files
|
|
92
|
+
import { originalTool1 } from './services/YOUR_SOURCE_1'
|
|
93
|
+
import { originalTool2 } from './utils/YOUR_SOURCE_2'
|
|
62
94
|
|
|
63
95
|
// ---------------------------------------------------------------------------
|
|
64
|
-
//
|
|
96
|
+
// Load elasticdash-test and share the module with ed_workflows.ts
|
|
65
97
|
// ---------------------------------------------------------------------------
|
|
66
98
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (entry.mode === 'mock-all') {
|
|
81
|
-
const data = entry.mockData ?? {}
|
|
82
|
-
const result = data[callNumber] !== undefined ? data[callNumber] : data[0]
|
|
83
|
-
return { mocked: true, result }
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (entry.mode === 'mock-specific') {
|
|
87
|
-
const indices = entry.callIndices ?? []
|
|
88
|
-
if (indices.includes(callNumber)) {
|
|
89
|
-
return { mocked: true, result: (entry.mockData ?? {})[callNumber] }
|
|
90
|
-
}
|
|
91
|
-
return { mocked: false }
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return { mocked: false }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function safeRecordToolCall(tool: string, input: any, result: any) {
|
|
98
|
-
if (!(globalThis as any).__ELASTICDASH_WORKER__) return
|
|
99
|
-
try {
|
|
100
|
-
const { recordToolCall } = await import('elasticdash-test')
|
|
101
|
-
recordToolCall(tool, input, result)
|
|
102
|
-
} catch { /* tracing must never block business logic */ }
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
100
|
+
type WrapToolFn = <T extends (...args: any[]) => any>(name: string, fn: T) => T
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
102
|
+
let wrapTool: WrapToolFn = (_name: string, fn: any) => fn
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
const _edModule = (eval('require') as (id: string) => any)('elasticdash-test')
|
|
107
|
+
wrapTool = _edModule.wrapTool ?? wrapTool
|
|
108
|
+
// Share the module instance with ed_workflows.ts so trace hooks use the same context
|
|
109
|
+
setElasticDashModule(_edModule)
|
|
110
|
+
} catch {
|
|
111
|
+
// elasticdash-test not available — all wrappers pass through to original functions
|
|
103
112
|
}
|
|
104
113
|
|
|
105
114
|
// ---------------------------------------------------------------------------
|
|
106
|
-
//
|
|
115
|
+
// Wrapped tools — one export per tool
|
|
107
116
|
// ---------------------------------------------------------------------------
|
|
108
117
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (mock.mocked) {
|
|
113
|
-
await safeRecordToolCall('YOUR_TOOL_1', input, mock.result)
|
|
114
|
-
return mock.result
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return await YOUR_TOOL_1_impl(input)
|
|
118
|
-
.then(async (res: any) => {
|
|
119
|
-
await safeRecordToolCall('YOUR_TOOL_1', input, res)
|
|
120
|
-
return res
|
|
121
|
-
})
|
|
122
|
-
.catch(async (err: any) => {
|
|
123
|
-
await safeRecordToolCall('YOUR_TOOL_1', input, err)
|
|
124
|
-
throw err
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export const YOUR_TOOL_2 = async (input: any) => {
|
|
129
|
-
const mock = resolveMock('YOUR_TOOL_2')
|
|
130
|
-
if (mock.mocked) {
|
|
131
|
-
await safeRecordToolCall('YOUR_TOOL_2', input, mock.result)
|
|
132
|
-
return mock.result
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return await YOUR_TOOL_2_impl(input)
|
|
136
|
-
.then(async (res: any) => {
|
|
137
|
-
await safeRecordToolCall('YOUR_TOOL_2', input, res)
|
|
138
|
-
return res
|
|
139
|
-
})
|
|
140
|
-
.catch(async (err: any) => {
|
|
141
|
-
await safeRecordToolCall('YOUR_TOOL_2', input, err)
|
|
142
|
-
throw err
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Pattern A template (dispatcher-based)
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
// ed_tools.ts
|
|
151
|
-
// Replace imports with your actual tool functions and source paths
|
|
152
|
-
import {
|
|
153
|
-
YOUR_TOOL_1 as _YOUR_TOOL_1,
|
|
154
|
-
YOUR_TOOL_2 as _YOUR_TOOL_2,
|
|
155
|
-
dispatchTool as _dispatchTool,
|
|
156
|
-
} from './YOUR_TOOLS_SOURCE'
|
|
157
|
-
|
|
158
|
-
async function withTrace<I, O>(
|
|
159
|
-
toolName: string,
|
|
160
|
-
input: I,
|
|
161
|
-
fn: (input: I) => Promise<O>,
|
|
162
|
-
): Promise<O> {
|
|
163
|
-
const result = await fn(input)
|
|
164
|
-
try {
|
|
165
|
-
const { recordToolCall } = await import('elasticdash-test')
|
|
166
|
-
recordToolCall(toolName, input, result)
|
|
167
|
-
} catch { /* tracing must never block business logic */ }
|
|
168
|
-
return result
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function YOUR_TOOL_1(input: Parameters<typeof _YOUR_TOOL_1>[0]) {
|
|
172
|
-
return withTrace('YOUR_TOOL_1', input, _YOUR_TOOL_1)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function YOUR_TOOL_2(input: Parameters<typeof _YOUR_TOOL_2>[0]) {
|
|
176
|
-
return withTrace('YOUR_TOOL_2', input, _YOUR_TOOL_2)
|
|
177
|
-
}
|
|
118
|
+
export const myTool1 = wrapTool('myTool1', async (input: any) => {
|
|
119
|
+
return await originalTool1(input)
|
|
120
|
+
})
|
|
178
121
|
|
|
179
|
-
export
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
default: return _dispatchTool(name, args)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
122
|
+
export const myTool2 = wrapTool('myTool2', async (input: any) => {
|
|
123
|
+
const { someField } = input as { someField: string }
|
|
124
|
+
return await originalTool2(someField)
|
|
125
|
+
})
|
|
186
126
|
```
|
|
187
127
|
|
|
188
|
-
###
|
|
189
|
-
|
|
190
|
-
For simpler setups where you don't need mock support or dashboard replays:
|
|
191
|
-
|
|
192
|
-
```ts
|
|
193
|
-
// ed_tools.ts
|
|
194
|
-
import { wrapTool } from 'elasticdash-test'
|
|
195
|
-
import { YOUR_TOOL_1 as YOUR_TOOL_1_impl } from './YOUR_SOURCE_PATH'
|
|
128
|
+
### Key patterns
|
|
196
129
|
|
|
197
|
-
|
|
198
|
-
|
|
130
|
+
- **`wrapTool(name, fn)`** wraps the function with automatic tracing, mocking, and telemetry. Falls back to a passthrough if `elasticdash-test` is not installed.
|
|
131
|
+
- **`eval('require')`** is used instead of `import()` to share the same module instance across `ed_tools.ts` and `ed_workflows.ts`. This avoids ESM/CJS dual-instance issues.
|
|
132
|
+
- **`setElasticDashModule`** shares the loaded module with `ed_workflows.ts` so `edStartTrace`/`edEndTrace` use the same tracing context as `wrapTool`.
|
|
133
|
+
- The exported name (e.g., `myTool1`) can differ from the original function name (e.g., `originalTool1`). The call sites in existing source files will be updated to use the new name in Step 4.
|
|
199
134
|
|
|
200
135
|
### Important rules
|
|
201
136
|
|
|
202
|
-
- The string name passed to `
|
|
137
|
+
- The string name passed to `wrapTool()` **must match** the exported function name exactly.
|
|
203
138
|
- Each tool function must accept a single input object and return a plain value (JSON-serializable).
|
|
204
139
|
- Tool functions must not close over HTTP context, framework state, or database clients — extract pure logic first.
|
|
205
140
|
|
|
@@ -219,92 +154,173 @@ export default nextConfig
|
|
|
219
154
|
|
|
220
155
|
## Step 3: Create `ed_workflows.ts`
|
|
221
156
|
|
|
222
|
-
Create `ed_workflows.ts` in the project root. This file
|
|
157
|
+
Create `ed_workflows.ts` in the project root. This file serves two purposes:
|
|
158
|
+
|
|
159
|
+
1. **Trace lifecycle hooks** (`edStartTrace`, `edEndTrace`) — called from route handlers to mark workflow boundaries
|
|
160
|
+
2. **Workflow exports** — callable functions for the ElasticDash dashboard and test runner
|
|
223
161
|
|
|
224
|
-
|
|
162
|
+
**Before writing this file**: Search the codebase for the main AI workflow functions — async functions that orchestrate LLM calls and tool calls (e.g., a chat handler, an agent loop, a pipeline function). Replace all `YOUR_WORKFLOW` and `YOUR_SOURCE_PATH` placeholders below with the actual function names and import paths.
|
|
163
|
+
|
|
164
|
+
### Trace lifecycle hooks
|
|
165
|
+
|
|
166
|
+
Every `ed_workflows.ts` should export `edStartTrace` and `edEndTrace`. These are called from route handlers (Step 4) to mark when a workflow starts and ends:
|
|
225
167
|
|
|
226
168
|
```ts
|
|
227
|
-
// ed_workflows.ts
|
|
228
|
-
|
|
229
|
-
|
|
169
|
+
// ed_workflows.ts — trace hooks (copy as-is)
|
|
170
|
+
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
+
let _ed: any = null
|
|
173
|
+
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
175
|
+
export function setElasticDashModule(mod: any): void {
|
|
176
|
+
_ed = mod
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const edStartTrace = async (workflowName: string): Promise<void> => {
|
|
180
|
+
if (!_ed) return
|
|
181
|
+
try {
|
|
182
|
+
await _ed.tryAutoInitHttpContext()
|
|
183
|
+
_ed.startTrace(workflowName)
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.error('[ed_workflows] edStartTrace error:', err)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const edEndTrace = (): void => {
|
|
190
|
+
if (!_ed) return
|
|
191
|
+
try {
|
|
192
|
+
_ed.endTrace()
|
|
193
|
+
} catch (err) {
|
|
194
|
+
console.error('[ed_workflows] edEndTrace error:', err)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
230
197
|
```
|
|
231
198
|
|
|
232
|
-
###
|
|
199
|
+
### Workflow exports — simple case
|
|
233
200
|
|
|
234
|
-
|
|
201
|
+
For non-framework projects where the workflow can be imported directly:
|
|
235
202
|
|
|
236
203
|
```ts
|
|
237
204
|
// ed_workflows.ts
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
export async function YOUR_WORKFLOW(input: { message: string; sessionId: string }) {
|
|
241
|
-
return _YOUR_HANDLER(input)
|
|
242
|
-
}
|
|
205
|
+
export { YOUR_WORKFLOW } from './YOUR_SOURCE_PATH'
|
|
243
206
|
```
|
|
244
207
|
|
|
245
|
-
###
|
|
208
|
+
### Workflow exports — HTTP mode (Next.js / Remix / framework projects)
|
|
246
209
|
|
|
247
|
-
|
|
210
|
+
For framework projects, the workflow calls the running dev server instead of importing the route handler:
|
|
248
211
|
|
|
249
212
|
```ts
|
|
250
|
-
//
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
import type { VercelAIStreamResult } from 'elasticdash-test'
|
|
254
|
-
import { POST } from './route'
|
|
213
|
+
// ed_workflows.ts
|
|
214
|
+
|
|
215
|
+
const APP_URL = process.env.APP_URL ?? 'http://localhost:3000'
|
|
255
216
|
|
|
256
|
-
export async
|
|
217
|
+
export const YOUR_WORKFLOW = async (input: {
|
|
257
218
|
messages: Array<{ role: string; content: string }>
|
|
258
219
|
sessionId?: string
|
|
259
|
-
}): Promise<
|
|
260
|
-
const
|
|
220
|
+
}): Promise<unknown> => {
|
|
221
|
+
const response = await fetch(`${APP_URL}/api/YOUR_ENDPOINT`, {
|
|
261
222
|
method: 'POST',
|
|
262
223
|
headers: { 'Content-Type': 'application/json' },
|
|
263
|
-
body: JSON.stringify(
|
|
224
|
+
body: JSON.stringify(input),
|
|
264
225
|
})
|
|
265
226
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const errorMessage = await response.text().catch(() => `HTTP ${response.status}`)
|
|
270
|
-
return { message: errorMessage, type: 'error', error: errorMessage }
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
const text = await response.text()
|
|
229
|
+
throw new Error(`HTTP ${response.status}: ${text}`)
|
|
271
230
|
}
|
|
272
231
|
|
|
273
|
-
|
|
274
|
-
recordToolCall('chatStream', args, result)
|
|
275
|
-
return result
|
|
232
|
+
return response.json()
|
|
276
233
|
}
|
|
277
234
|
```
|
|
278
235
|
|
|
279
|
-
Then re-export from `ed_workflows.ts`:
|
|
280
|
-
|
|
281
|
-
```ts
|
|
282
|
-
// ed_workflows.ts
|
|
283
|
-
export { chatStreamHandler } from './app/api/chat-stream/chatStreamHandler'
|
|
284
|
-
```
|
|
285
|
-
|
|
286
236
|
### Requirements for all workflow exports
|
|
287
237
|
|
|
288
238
|
- Accept only JSON-serializable inputs (strings, numbers, arrays, plain objects)
|
|
289
239
|
- Return only JSON-serializable outputs
|
|
290
240
|
- Must not depend on framework runtime APIs, HTTP request context, or live service clients
|
|
291
|
-
- If a dependency is non-serializable (e.g., database client), instantiate it inside `ed_workflows.ts`, not passed as a parameter
|
|
292
241
|
|
|
293
242
|
---
|
|
294
243
|
|
|
295
|
-
## Step 4: Update
|
|
244
|
+
## Step 4: Update existing source files to use `ed_tools`
|
|
245
|
+
|
|
246
|
+
> **This step modifies the user's existing source files.** The files that call tool functions must import from `ed_tools` instead of the original source, so that all tool calls go through the ElasticDash tracing layer. Similarly, workflow entry points (route handlers, etc.) must call `edStartTrace` / `edEndTrace` from `ed_workflows`.
|
|
247
|
+
|
|
248
|
+
### Architecture after integration
|
|
296
249
|
|
|
297
|
-
|
|
250
|
+
```
|
|
251
|
+
ed_tools.ts
|
|
252
|
+
├── imports original functions from services/utils
|
|
253
|
+
├── wraps each with wrapTool() for tracing
|
|
254
|
+
└── exports wrapped versions with the SAME or similar names
|
|
255
|
+
|
|
256
|
+
ed_workflows.ts
|
|
257
|
+
├── exports edStartTrace / edEndTrace for workflow-level tracing
|
|
258
|
+
└── exports workflow functions (for dashboard/test runner)
|
|
259
|
+
|
|
260
|
+
Existing source files (MODIFIED):
|
|
261
|
+
app/api/chat/route.ts
|
|
262
|
+
├── BEFORE: import { myTool } from '@/services/myService'
|
|
263
|
+
├── AFTER: import { myTool } from '@/ed_tools'
|
|
264
|
+
├── ADDED: import { edStartTrace, edEndTrace } from '@/ed_workflows'
|
|
265
|
+
└── ADDED: await edStartTrace('workflowName') at handler entry
|
|
266
|
+
edEndTrace() at handler exit
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### What to do
|
|
270
|
+
|
|
271
|
+
**1. Find every file that calls a tool function and update its imports:**
|
|
272
|
+
|
|
273
|
+
For each tool exported from `ed_tools.ts`, search the codebase for files that import the original function. Update the import to come from `ed_tools` instead.
|
|
298
274
|
|
|
299
275
|
```ts
|
|
300
|
-
// BEFORE
|
|
301
|
-
import {
|
|
276
|
+
// BEFORE — app/api/chat/route.ts
|
|
277
|
+
import { clarifyAndRefineUserInput } from '@/utils/queryRefinement'
|
|
278
|
+
import { dynamicApiRequest } from '@/services/apiService'
|
|
302
279
|
|
|
303
|
-
// AFTER
|
|
304
|
-
import {
|
|
280
|
+
// AFTER — app/api/chat/route.ts
|
|
281
|
+
import { queryRefinement } from '@/ed_tools'
|
|
282
|
+
import { apiService } from '@/ed_tools'
|
|
305
283
|
```
|
|
306
284
|
|
|
307
|
-
|
|
285
|
+
```ts
|
|
286
|
+
// BEFORE — app/api/chat/executor.ts
|
|
287
|
+
import { dynamicApiRequest } from '@/services/apiService'
|
|
288
|
+
|
|
289
|
+
// AFTER — app/api/chat/executor.ts
|
|
290
|
+
import { apiService } from '@/ed_tools'
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**2. Add trace hooks to route handlers / workflow entry points:**
|
|
294
|
+
|
|
295
|
+
At the top of each route handler or workflow entry function, add `edStartTrace` and `edEndTrace`:
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
// app/api/chat/route.ts
|
|
299
|
+
import { edStartTrace, edEndTrace } from '@/ed_workflows'
|
|
300
|
+
|
|
301
|
+
export async function POST(req: Request) {
|
|
302
|
+
await edStartTrace('chatHandler')
|
|
303
|
+
try {
|
|
304
|
+
// ... existing handler logic, now using tools from ed_tools
|
|
305
|
+
} finally {
|
|
306
|
+
edEndTrace()
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**3. Update call sites if the wrapped function has a different name:**
|
|
312
|
+
|
|
313
|
+
If `ed_tools.ts` exports a tool under a different name than the original (e.g., `queryRefinement` wrapping `clarifyAndRefineUserInput`), update the call sites to use the new name.
|
|
314
|
+
|
|
315
|
+
### What NOT to modify
|
|
316
|
+
|
|
317
|
+
- **Do not modify `ed_tools.ts` imports** — it must still import from the original source files.
|
|
318
|
+
- **Do not modify the original tool implementation files** (e.g., `services/apiService.ts`, `utils/queryRefinement.ts`) — they stay as-is.
|
|
319
|
+
- **Do not modify files that don't call tool functions** — only update files that directly import and call the wrapped tools.
|
|
320
|
+
|
|
321
|
+
### When to ask the user
|
|
322
|
+
|
|
323
|
+
If you are not confident about a change — e.g., a function might be a utility rather than a tool, or it's unclear whether a file should use the wrapped version — **ask the user** before modifying that file. For clear tool calls (API services, database queries, LLM calls), proceed automatically.
|
|
308
324
|
|
|
309
325
|
---
|
|
310
326
|
|
|
@@ -425,7 +441,30 @@ npx ed ed-test --no-upload
|
|
|
425
441
|
|
|
426
442
|
---
|
|
427
443
|
|
|
428
|
-
## Step 8:
|
|
444
|
+
## Step 8: Validate the integration
|
|
445
|
+
|
|
446
|
+
After all files are created, validate the setup by establishing a socket.io connection to the ElasticDash backend. Run the `observe` command — it connects to the server, authenticates with the API key, and registers the project's tools and workflows:
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
npx elasticdash observe
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Expected output on success:**
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
[elasticdash] Observability active
|
|
456
|
+
Session ID : <uuid>
|
|
457
|
+
Server : https://server.elasticdash.com
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
This confirms:
|
|
461
|
+
- `ELASTICDASH_API_URL` and `ELASTICDASH_API_KEY` are valid
|
|
462
|
+
- The socket.io connection to the backend is established
|
|
463
|
+
- The SDK can discover `ed_tools.ts` and `ed_workflows.ts`
|
|
464
|
+
|
|
465
|
+
**If it fails:** Check that `.env` has valid `ELASTICDASH_API_URL` and `ELASTICDASH_API_KEY` values. If the API key is rejected, the user needs to get a new one from https://app.elasticdash.com.
|
|
466
|
+
|
|
467
|
+
After validation, stop the observe process (Ctrl+C) and inform the user that ElasticDash is integrated. Provide these commands for ongoing use:
|
|
429
468
|
|
|
430
469
|
```bash
|
|
431
470
|
# Run aiTest tests
|
|
@@ -437,6 +476,9 @@ npx ed ed-test --no-upload
|
|
|
437
476
|
# Open the dashboard
|
|
438
477
|
npx elasticdash dashboard
|
|
439
478
|
|
|
479
|
+
# Start observability (connect to backend for live tracing)
|
|
480
|
+
npx elasticdash observe
|
|
481
|
+
|
|
440
482
|
# Record a trace fixture
|
|
441
483
|
ELASTICDASH_CAPTURE_TRACE=1 tsx your-workflow.ts
|
|
442
484
|
```
|
|
@@ -542,16 +584,12 @@ After integration, verify these files exist:
|
|
|
542
584
|
|
|
543
585
|
```
|
|
544
586
|
your-project/
|
|
545
|
-
|
|
546
|
-
|
|
587
|
+
.env # ELASTICDASH_API_URL and ELASTICDASH_API_KEY set
|
|
588
|
+
ed_tools.ts # Instrumented tool wrappers (real function names, not placeholders)
|
|
589
|
+
ed_workflows.ts # Workflow exports using tools from ed_tools.ts
|
|
547
590
|
elasticdash.config.ts # Test runner config
|
|
548
591
|
package.json # dashboard:ai and test:ai scripts added
|
|
549
592
|
.gitignore # .temp/ and .ed_traces/ added
|
|
550
593
|
```
|
|
551
594
|
|
|
552
|
-
Verify
|
|
553
|
-
|
|
554
|
-
```bash
|
|
555
|
-
npx elasticdash test # Should discover and run *.ai.test.ts files
|
|
556
|
-
npx elasticdash dashboard # Should open the dashboard UI
|
|
557
|
-
```
|
|
595
|
+
Verify by running `npx elasticdash observe` — a successful socket.io connection confirms the integration is complete.
|