@hedeqiang/dsh-nl2sql 0.13.1 → 0.14.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/CHANGELOG.md +14 -1
- package/bin/nl2sql-mcp.mjs +117 -40
- package/docs/mcp.md +152 -41
- package/drivers.js +16 -3
- package/lib/client.js +197 -14
- package/package.json +1 -1
- package/service/mcp.js +966 -100
- package/service/query.js +11 -3
- package/service/shared.js +9 -0
package/service/query.js
CHANGED
|
@@ -9,7 +9,7 @@ import { admitSql, prepareSql, stripSql } from '../sql-guard.js'
|
|
|
9
9
|
import { cacheKey } from '../store.js'
|
|
10
10
|
import { createHash } from 'node:crypto'
|
|
11
11
|
import { writeXlsx } from '../xlsx.js'
|
|
12
|
-
import { RESULT_CACHE_LIMIT, SENSITIVE_NAME, UserError, columnKind, fillChartHint, fmtNum, maskValue, newId, normalizeChart, suggestChart, summarize } from './shared.js'
|
|
12
|
+
import { RESULT_CACHE_LIMIT, SENSITIVE_NAME, UserError, callContext, columnKind, fillChartHint, fmtNum, maskValue, newId, normalizeChart, suggestChart, summarize } from './shared.js'
|
|
13
13
|
|
|
14
14
|
export const methods = {
|
|
15
15
|
// ---------------------------------------------------------------- query
|
|
@@ -36,6 +36,7 @@ export const methods = {
|
|
|
36
36
|
await this.save()
|
|
37
37
|
throw new UserError('nl2sql/access-denied', denied)
|
|
38
38
|
}
|
|
39
|
+
callContext.getStore()?.phase?.('admitted', { datasource: ds.name, title })
|
|
39
40
|
let appliedFilters = []
|
|
40
41
|
if (filters?.length) {
|
|
41
42
|
let f
|
|
@@ -108,15 +109,22 @@ export const methods = {
|
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
const started = Date.now()
|
|
112
|
+
// Optional per-call context (MCP tools/call): progress phases and cancellation.
|
|
113
|
+
const call = callContext.getStore()
|
|
114
|
+
call?.phase?.('running', { datasource: ds.name, title })
|
|
111
115
|
let res
|
|
112
116
|
try {
|
|
113
|
-
|
|
117
|
+
if (call?.signal?.aborted) throw new UserError('query/cancelled', '查询已取消')
|
|
118
|
+
res = await this.withDriver(ds, d => d.query(prepared, { timeoutMs: settings.timeoutMs, maxRows: settings.maxRows, ...(call?.signal ? { signal: call.signal } : {}) }))
|
|
119
|
+
if (call?.signal?.aborted) throw new UserError('query/cancelled', '查询已取消')
|
|
114
120
|
} catch (error) {
|
|
115
|
-
|
|
121
|
+
const cancelled = error.code === 'query/cancelled' || call?.signal?.aborted
|
|
122
|
+
this.audit({ ds, sessionId, source, sql: admitted.sql, title, status: cancelled ? 'cancelled' : 'error', error: cancelled ? 'cancelled by the client' : error.message, elapsedMs: Date.now() - started, actor })
|
|
116
123
|
await this.save()
|
|
117
124
|
throw error
|
|
118
125
|
}
|
|
119
126
|
const elapsedMs = Date.now() - started
|
|
127
|
+
call?.phase?.('fetched', { datasource: ds.name, title, rows: Math.min(res.rows.length, settings.maxRows) })
|
|
120
128
|
const truncated = res.rows.length > settings.maxRows
|
|
121
129
|
let cells = truncated ? res.rows.slice(0, settings.maxRows) : res.rows
|
|
122
130
|
const schema = fullSchema
|
package/service/shared.js
CHANGED
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
import { createHash, randomBytes } from 'node:crypto'
|
|
5
5
|
import { DIALECTS, describeError } from '../drivers.js'
|
|
6
6
|
import { sqliteDialectHints } from '../sqlite-driver.js'
|
|
7
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Per-call context for long requests (MCP tools/call): { signal?: AbortSignal, phase?(name, info) }.
|
|
11
|
+
* runQuery reports phases and passes the signal to drivers that can cancel a running statement.
|
|
12
|
+
*/
|
|
13
|
+
export const callContext = new AsyncLocalStorage()
|
|
8
14
|
|
|
9
15
|
export const SUPPORTED_TYPES = Object.keys(DIALECTS)
|
|
10
16
|
|
|
@@ -231,6 +237,9 @@ RECORD_REF.bitableRun = 'syncId'
|
|
|
231
237
|
// Daily digest runs (service/proactive.js).
|
|
232
238
|
RECORD_LIMITS.digestRun = 1000
|
|
233
239
|
RECORD_REF.digestRun = 'digestId'
|
|
240
|
+
// MCP per-token call log (service/mcp.js): time, method/tool, data source, ms, status, rows.
|
|
241
|
+
RECORD_LIMITS.mcpCall = 5000
|
|
242
|
+
RECORD_REF.mcpCall = 'tokenId'
|
|
234
243
|
|
|
235
244
|
/**
|
|
236
245
|
* Growing logs (audit history, feedback, push deliveries, alert events, admin
|