@stratta/mcp 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/README.md +47 -28
- package/dist/confirm.d.ts +10 -1
- package/dist/confirm.js +37 -24
- package/dist/errors.js +40 -0
- package/dist/tools/catalog.gen.js +377 -0
- package/dist/tools/dossier.d.ts +136 -0
- package/dist/tools/dossier.js +282 -0
- package/dist/tools/site.d.ts +46 -0
- package/dist/tools/site.js +121 -1
- package/package.json +1 -1
- package/skills/consult-stratta/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ https://stratta.ch/mcp
|
|
|
34
34
|
That is the shorter path, the one the dashboard walks you through for Claude,
|
|
35
35
|
ChatGPT, Claude Code, Codex, Cursor, VS Code, Gemini CLI and Windsurf, and the
|
|
36
36
|
only one that works in an agent running in the cloud (claude.ai, ChatGPT). It
|
|
37
|
-
serves
|
|
37
|
+
serves 54 of the 55 tools below, **ingestion included**: the pre-pass script is
|
|
38
38
|
downloaded from https://stratta.ch/ingest-prepass.py when it is not on disk.
|
|
39
39
|
See https://stratta.ch/docs/en/guides/connect-remote.
|
|
40
40
|
|
|
@@ -176,8 +176,8 @@ named `E2E dossier <timestamp>` and does not delete it.
|
|
|
176
176
|
|
|
177
177
|
## Tools exposed
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
serves the same
|
|
179
|
+
55 tools, generated from one catalogue shared with the remote connector (which
|
|
180
|
+
serves the same 54, everything minus `add_attachment`).
|
|
181
181
|
|
|
182
182
|
**Read** (10 tools — query the norms of your workspace):
|
|
183
183
|
|
|
@@ -194,31 +194,50 @@ serves the same 33 minus `add_attachment`).
|
|
|
194
194
|
| `get_figure` | Retrieve a figure inline (base64 ImageContent). |
|
|
195
195
|
| `get_cross_refs` | Outgoing cross-refs from a section to other norms. |
|
|
196
196
|
|
|
197
|
-
**Site** (
|
|
198
|
-
|
|
199
|
-
| Tool
|
|
200
|
-
|
|
|
201
|
-
| `scan_site`
|
|
202
|
-
| `get_site_context`
|
|
203
|
-
| `get_boreholes`
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
|
208
|
-
|
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
| `
|
|
217
|
-
| `
|
|
218
|
-
| `
|
|
219
|
-
| `
|
|
220
|
-
| `
|
|
221
|
-
| `
|
|
197
|
+
**Site** (10 tools — what public Swiss registers know about a plot, and the site sheet as the app shows it):
|
|
198
|
+
|
|
199
|
+
| Tool | Purpose |
|
|
200
|
+
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
201
|
+
| `scan_site` | Collect municipality, parcel, elevation, geology, nearby boreholes, polluted sites, hazards and noise class around a Swiss address. |
|
|
202
|
+
| `get_site_context` | Read what the scan settled, and — separately — what it could not, with the reason. |
|
|
203
|
+
| `get_boreholes` | Read the boreholes nearest the site with their logged strata, SIA 261 ground class, water table, and links to cantonal documents. |
|
|
204
|
+
| `list_sites` | The site sheets of the organisation, with their dossier, canton and scan status. |
|
|
205
|
+
| `get_site` | The sheet as the app shows it: every fact with its key, status, source, notice and attribution, and the scan with its sources. |
|
|
206
|
+
| `get_site_section` | The section along the axis: terrain, modelled bedrock, geology bands and the boreholes of the corridor with their logs. |
|
|
207
|
+
| `list_site_overlays` | The map areas around the point (polluted sites, hazards, water protection), with distance and coverage of the site point. |
|
|
208
|
+
| `get_groundwater_contours` | The cantonal piezometric contours stored by the scan, with the aquifer name and elevation. |
|
|
209
|
+
| `list_site_photos` | The photos uploaded on the sheet, with position, direction, instant and note. No image, no link. |
|
|
210
|
+
| `list_site_neighbours` | The organisation's other sheets within a radius, with the distance and the geological unit their scan established. |
|
|
211
|
+
|
|
212
|
+
**Dossier** (25 tools — keep what was decided on a project, and everything the dossier page can do to a question):
|
|
213
|
+
|
|
214
|
+
| Tool | Purpose |
|
|
215
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
216
|
+
| `list_dossiers` | Your organisation's dossiers, most recently touched first, with open-question counts and site id. |
|
|
217
|
+
| `open_dossier` | Open a project's dossier, creating it if needed. Idempotent on the name. |
|
|
218
|
+
| `open_question` | Open one question to settle, with optional named options. Idempotent on the title. |
|
|
219
|
+
| `save_finding` | Record one piece of evidence: a cited article, a retained value and why, an observation. |
|
|
220
|
+
| `record_decision` | Settle a question with a decision the engineer has confirmed, and the retained option. |
|
|
221
|
+
| `load_dossier` | Reload everything: questions with their evidence and decisions, open ones first. |
|
|
222
|
+
| `resolve_question` | Close a question without a decision, or reopen one. The evidence stays. |
|
|
223
|
+
| `list_attachments` | The project attachments of a dossier: site reports, borehole logs, minutes, data sheets. |
|
|
224
|
+
| `read_attachment` | Read an attachment's text as Markdown, page by page. |
|
|
225
|
+
| `search_in_dossier` | Full-text search over a dossier's attachments, with the page of each hit. |
|
|
226
|
+
| `add_attachment` | Upload a file from the user's machine to a dossier (PDF, DOCX, XLSX, images, text). Local server only. |
|
|
227
|
+
| `list_templates` | The checklists the organisation wrote for its types of structure. |
|
|
228
|
+
| `apply_template` | Open a template's questions in a dossier and file the clauses that resolve in the corpus. |
|
|
229
|
+
| `list_questions` | The questions of a dossier, paginated, with status, assignee, due date, options and decision title. |
|
|
230
|
+
| `get_question` | One question in full: options, decision, evidence with every citation field, comments with authors. |
|
|
231
|
+
| `get_dossier_activity` | The history of a dossier, most recent first, paginated: who did what, from the app or an agent. |
|
|
232
|
+
| `list_exports` | The verification notes and journals exported from a dossier, with hash and trusted timestamp. |
|
|
233
|
+
| `update_question` | Reword a question, assign it by e-mail address, set or clear its due date. |
|
|
234
|
+
| `add_option` | Add one way of settling a question. Idempotent on the name. |
|
|
235
|
+
| `update_option` | Rename or describe an option, or mark it retained (the others are released). |
|
|
236
|
+
| `delete_option` | Remove an option; its evidence stays on the question. Asks the user first. |
|
|
237
|
+
| `delete_question` | Delete a question opened by mistake; its evidence stays, unfiled. Asks the user first. |
|
|
238
|
+
| `add_comment` | Leave a signed remark on a dossier, a question or an entry. |
|
|
239
|
+
| `update_entry` | Correct an entry's wording, value, confidence or citation in place. |
|
|
240
|
+
| `attach_entry` | File an entry under a question and optionally an option, or unfile it. |
|
|
222
241
|
|
|
223
242
|
A dossier is read, annotated, reviewed and exported from
|
|
224
243
|
[stratta.ch/dossiers](https://stratta.ch/dossiers).
|
package/dist/confirm.d.ts
CHANGED
|
@@ -9,7 +9,16 @@ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
|
9
9
|
* `confirmed: true` when it does not. The Convex function never sees the
|
|
10
10
|
* difference.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
type Confirmation = {
|
|
13
|
+
/** What is at stake, as the dialog names it. */
|
|
14
|
+
what: string;
|
|
15
|
+
/** The one line the user reads, built from the arguments. */
|
|
16
|
+
summary: (args: Record<string, unknown>) => string;
|
|
17
|
+
/** The question asked. A removal never asks "Record it". */
|
|
18
|
+
prompt: string;
|
|
19
|
+
};
|
|
20
|
+
export declare const CONFIRMED_TOOLS: Record<string, Confirmation>;
|
|
13
21
|
export declare const CONFIRMATION_HINT: string;
|
|
14
22
|
/** `null` when the call may proceed, a tool result to return otherwise. */
|
|
15
23
|
export declare function confirmWithUser(server: Pick<Server, 'getClientCapabilities' | 'elicitInput'>, toolName: string, args: Record<string, unknown>): Promise<CallToolResult | null>;
|
|
24
|
+
export {};
|
package/dist/confirm.js
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
1
|
+
const decisionSummary = (args) => [
|
|
2
|
+
args.title,
|
|
3
|
+
args.value ? `= ${String(args.value)}` : null,
|
|
4
|
+
args.retainedOption ? `(option ${String(args.retainedOption)})` : null,
|
|
5
|
+
]
|
|
6
|
+
.filter(Boolean)
|
|
7
|
+
.map(String)
|
|
8
|
+
.join(' ');
|
|
10
9
|
export const CONFIRMED_TOOLS = {
|
|
11
|
-
record_decision:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
: '
|
|
10
|
+
record_decision: {
|
|
11
|
+
what: 'Decision',
|
|
12
|
+
summary: decisionSummary,
|
|
13
|
+
prompt: 'Record it in the dossier?',
|
|
14
|
+
},
|
|
15
|
+
resolve_question: {
|
|
16
|
+
what: 'Question',
|
|
17
|
+
summary: (args) => args.resolved === false
|
|
18
|
+
? 'reopen this question'
|
|
19
|
+
: 'close this question without a decision',
|
|
20
|
+
prompt: 'Record it in the dossier?',
|
|
21
|
+
},
|
|
22
|
+
// The two deletions of 0.14.0. The gate only sees ids, so the line says
|
|
23
|
+
// what goes and what stays rather than naming the row.
|
|
24
|
+
delete_question: {
|
|
25
|
+
what: 'Question',
|
|
26
|
+
summary: () => 'delete this question with its options, its comments and its decision; ' +
|
|
27
|
+
'its evidence stays in the dossier, unfiled',
|
|
28
|
+
prompt: 'Delete it?',
|
|
29
|
+
},
|
|
30
|
+
delete_option: {
|
|
31
|
+
what: 'Option',
|
|
32
|
+
summary: () => 'remove this option; the evidence filed under it stays on the question',
|
|
33
|
+
prompt: 'Remove it?',
|
|
34
|
+
},
|
|
22
35
|
};
|
|
23
36
|
export const CONFIRMATION_HINT = 'Not recorded: this client cannot ask the user directly. Confirm the ' +
|
|
24
37
|
'decision with the user in the conversation, then call again with ' +
|
|
25
38
|
'confirmed: true.';
|
|
26
39
|
/** `null` when the call may proceed, a tool result to return otherwise. */
|
|
27
40
|
export async function confirmWithUser(server, toolName, args) {
|
|
28
|
-
const
|
|
29
|
-
if (!
|
|
41
|
+
const confirmation = CONFIRMED_TOOLS[toolName];
|
|
42
|
+
if (!confirmation || args.confirmed === true)
|
|
30
43
|
return null;
|
|
31
44
|
if (!server.getClientCapabilities()?.elicitation) {
|
|
32
45
|
return {
|
|
@@ -37,10 +50,10 @@ export async function confirmWithUser(server, toolName, args) {
|
|
|
37
50
|
}
|
|
38
51
|
const result = await server.elicitInput({
|
|
39
52
|
mode: 'form',
|
|
40
|
-
message: `${
|
|
53
|
+
message: `${confirmation.what}: ${confirmation.summary(args)}\n\n${confirmation.prompt}`,
|
|
41
54
|
requestedSchema: {
|
|
42
55
|
type: 'object',
|
|
43
|
-
properties: { confirm: { type: 'boolean', title: '
|
|
56
|
+
properties: { confirm: { type: 'boolean', title: 'Confirm' } },
|
|
44
57
|
required: ['confirm'],
|
|
45
58
|
},
|
|
46
59
|
});
|
package/dist/errors.js
CHANGED
|
@@ -47,6 +47,7 @@ const HELP = {
|
|
|
47
47
|
RATE_LIMITED: `${DOCS}/resources/troubleshooting`,
|
|
48
48
|
DOSSIER_NOT_FOUND: `${DOCS}/mcp/dossier-tools`,
|
|
49
49
|
DOSSIER_CLOSED: `${DOCS}/guides/suivre-un-projet`,
|
|
50
|
+
READ_ONLY: `${DOCS}/account/plans`,
|
|
50
51
|
ENTRY_NOT_FOUND: `${DOCS}/mcp/dossier-tools`,
|
|
51
52
|
TOO_MANY_DOSSIERS: `${DOCS}/mcp/dossier-tools`,
|
|
52
53
|
TOO_MANY_ENTRIES: `${DOCS}/mcp/dossier-tools`,
|
|
@@ -129,6 +130,45 @@ export function formatToolError(err) {
|
|
|
129
130
|
"Cette entrée n'existe pas, ou elle appartient à un autre dossier.",
|
|
130
131
|
'Rechargez le dossier avec `load_dossier` pour obtenir des identifiants à jour.',
|
|
131
132
|
]);
|
|
133
|
+
case 'QUESTION_NOT_FOUND':
|
|
134
|
+
return withHelp(data, [
|
|
135
|
+
"Cette question n'existe pas dans votre organisation, ou elle appartient à un autre dossier.",
|
|
136
|
+
'Appelez `list_questions` sur le dossier pour obtenir des identifiants à jour.',
|
|
137
|
+
]);
|
|
138
|
+
case 'OPTION_NOT_FOUND':
|
|
139
|
+
return withHelp(data, [
|
|
140
|
+
"Cette option n'existe pas, ou elle appartient à une autre question.",
|
|
141
|
+
'Appelez `get_question` pour lire les options et leurs identifiants.',
|
|
142
|
+
]);
|
|
143
|
+
case 'OPTION_WITHOUT_QUESTION':
|
|
144
|
+
return withHelp(data, [
|
|
145
|
+
'Une option se rattache à une question : donnez `questionId` avec `optionId`.',
|
|
146
|
+
]);
|
|
147
|
+
case 'DECISION_IS_BOUND':
|
|
148
|
+
return withHelp(data, [
|
|
149
|
+
'Une décision appartient à sa question et ne se déplace pas. Corrigez-la avec `update_entry`, ou rouvrez la question avec `resolve_question` (resolved: false).',
|
|
150
|
+
]);
|
|
151
|
+
case 'NOT_A_MEMBER':
|
|
152
|
+
return withHelp(data, [
|
|
153
|
+
"Cette adresse ne correspond à aucun membre de l'organisation. Demandez à l'utilisateur l'adresse exacte, ou laissez la question sans responsable.",
|
|
154
|
+
]);
|
|
155
|
+
case 'INVALID_DATE':
|
|
156
|
+
return withHelp(data, [
|
|
157
|
+
'La date attendue est un jour ISO, par exemple « 2026-10-15 ».',
|
|
158
|
+
]);
|
|
159
|
+
case 'SITE_NOT_FOUND':
|
|
160
|
+
return withHelp(data, [
|
|
161
|
+
"Cette fiche de site n'existe pas dans votre organisation.",
|
|
162
|
+
'Appelez `list_sites`, ou lisez `siteId` sur la ligne du dossier dans `list_dossiers`.',
|
|
163
|
+
]);
|
|
164
|
+
case 'TOO_MANY_QUESTIONS':
|
|
165
|
+
return withHelp(data, [
|
|
166
|
+
'Ce dossier a atteint son plafond de questions. Ne réessayez pas ; closez ou supprimez celles qui ne comptent plus.',
|
|
167
|
+
]);
|
|
168
|
+
case 'TOO_MANY_OPTIONS':
|
|
169
|
+
return withHelp(data, [
|
|
170
|
+
'Cette question a déjà dix options, le maximum. Ne réessayez pas ; retirez-en une avec `delete_option` si une nouvelle est nécessaire.',
|
|
171
|
+
]);
|
|
132
172
|
case 'TOO_MANY_DOSSIERS':
|
|
133
173
|
return withHelp(data, [
|
|
134
174
|
'Cette organisation a atteint son plafond de dossiers.',
|
|
@@ -252,6 +252,136 @@ export const CATALOG = [
|
|
|
252
252
|
"siteId": "Site id returned by scan_site."
|
|
253
253
|
}
|
|
254
254
|
},
|
|
255
|
+
{
|
|
256
|
+
"name": "list_sites",
|
|
257
|
+
"title": "Site sheets",
|
|
258
|
+
"description": "List the site sheets of the organization, most recently touched first, each with the dossier it belongs to, the municipality and canton, the search radius and the status of its current scan. Call it when the user names a site or an address rather than a dossier, or to find the siteId of a sheet opened from the app; a dossier row from list_dossiers also carries its siteId.",
|
|
259
|
+
"annotations": {
|
|
260
|
+
"readOnlyHint": true,
|
|
261
|
+
"destructiveHint": false,
|
|
262
|
+
"idempotentHint": true,
|
|
263
|
+
"openWorldHint": false
|
|
264
|
+
},
|
|
265
|
+
"transports": [
|
|
266
|
+
"stdio",
|
|
267
|
+
"remote"
|
|
268
|
+
],
|
|
269
|
+
"params": {
|
|
270
|
+
"limit": "How many sites to return, 1 to 200. Default 50; truncated says when more exist."
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"name": "get_site",
|
|
275
|
+
"title": "Read a site sheet",
|
|
276
|
+
"description": "Read a site sheet as the app shows it: every fact with its stable key, its status (established, indicative, absent, uncovered), its source with the date the data was current, the official notice and attribution when the source carries one, and the scan with each source and whether it answered. get_site_context is the summary shaped for an answer; call this when you need to quote a source line, cite a fact key in save_finding, or tell the user which source failed. Facts are registers, never a geotechnical study.",
|
|
277
|
+
"annotations": {
|
|
278
|
+
"readOnlyHint": true,
|
|
279
|
+
"destructiveHint": false,
|
|
280
|
+
"idempotentHint": true,
|
|
281
|
+
"openWorldHint": false
|
|
282
|
+
},
|
|
283
|
+
"transports": [
|
|
284
|
+
"stdio",
|
|
285
|
+
"remote"
|
|
286
|
+
],
|
|
287
|
+
"params": {
|
|
288
|
+
"siteId": "Site id from scan_site, list_sites or a dossier row."
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"name": "get_site_section",
|
|
293
|
+
"title": "Read the section",
|
|
294
|
+
"description": "Read the geological section drawn on a site sheet: the axis from A to B, the corridor width, the measured terrain line, the modelled bedrock top, the geology bands sampled along the axis, and the boreholes inside the corridor with their logged strata, projected on the axis. Call it when the question is about what lies along a line rather than at a point. Without an axis drawn in the app, it says so and returns no lines. Nothing is interpolated between boreholes.",
|
|
295
|
+
"annotations": {
|
|
296
|
+
"readOnlyHint": true,
|
|
297
|
+
"destructiveHint": false,
|
|
298
|
+
"idempotentHint": true,
|
|
299
|
+
"openWorldHint": false
|
|
300
|
+
},
|
|
301
|
+
"transports": [
|
|
302
|
+
"stdio",
|
|
303
|
+
"remote"
|
|
304
|
+
],
|
|
305
|
+
"params": {
|
|
306
|
+
"siteId": "Site id from scan_site, list_sites or a dossier row.",
|
|
307
|
+
"maxPoints": "How many points of the terrain and bedrock lines to return, evenly spaced, 2 to 200. Default 60."
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"name": "list_site_overlays",
|
|
312
|
+
"title": "Map areas around a site",
|
|
313
|
+
"description": "List the areas the site map draws around the point: polluted sites, natural hazard zones and water protection sectors read from the canton, each with whether it covers the site point or how many metres away it stops, its area and its layer. Coordinates are left out unless asked for. Call it after get_site_context when a constraint is near and the user asks how near; the sheet answers at the point, this answers in the radius.",
|
|
314
|
+
"annotations": {
|
|
315
|
+
"readOnlyHint": true,
|
|
316
|
+
"destructiveHint": false,
|
|
317
|
+
"idempotentHint": true,
|
|
318
|
+
"openWorldHint": false
|
|
319
|
+
},
|
|
320
|
+
"transports": [
|
|
321
|
+
"stdio",
|
|
322
|
+
"remote"
|
|
323
|
+
],
|
|
324
|
+
"params": {
|
|
325
|
+
"siteId": "Site id from scan_site, list_sites or a dossier row.",
|
|
326
|
+
"includeGeometry": "Return the polygon rings in LV95 as well. Default false: rings run to hundreds of points."
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"name": "get_groundwater_contours",
|
|
331
|
+
"title": "Piezometric contours",
|
|
332
|
+
"description": "Read the cantonal piezometric contours the scan stored around a site: for each contour the aquifer name, the water table elevation in metres above sea level and the source layer. Cantons that publish none return an empty list and say whether the reading happened. A contour is the canton's interpretation of an aquifer, not a measurement at the site: prefer a water table logged in a nearby borehole (get_boreholes) when one exists, and quote a contour with its name.",
|
|
333
|
+
"annotations": {
|
|
334
|
+
"readOnlyHint": true,
|
|
335
|
+
"destructiveHint": false,
|
|
336
|
+
"idempotentHint": true,
|
|
337
|
+
"openWorldHint": false
|
|
338
|
+
},
|
|
339
|
+
"transports": [
|
|
340
|
+
"stdio",
|
|
341
|
+
"remote"
|
|
342
|
+
],
|
|
343
|
+
"params": {
|
|
344
|
+
"siteId": "Site id from scan_site, list_sites or a dossier row.",
|
|
345
|
+
"includeGeometry": "Return the contour vertices in LV95 as well. Default false."
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"name": "list_site_photos",
|
|
350
|
+
"title": "Site photos",
|
|
351
|
+
"description": "List the photos the engineer uploaded on a site sheet: name, position in LV95 when the photo carries one (from its EXIF data or placed by hand), shooting direction, the instant the camera recorded, and the note written on it. No image is returned and no link: the photo is looked at in the app. Call it to know what was observed on site and when, before writing an observation.",
|
|
352
|
+
"annotations": {
|
|
353
|
+
"readOnlyHint": true,
|
|
354
|
+
"destructiveHint": false,
|
|
355
|
+
"idempotentHint": true,
|
|
356
|
+
"openWorldHint": false
|
|
357
|
+
},
|
|
358
|
+
"transports": [
|
|
359
|
+
"stdio",
|
|
360
|
+
"remote"
|
|
361
|
+
],
|
|
362
|
+
"params": {
|
|
363
|
+
"siteId": "Site id from scan_site, list_sites or a dossier row."
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"name": "list_site_neighbours",
|
|
368
|
+
"title": "Neighbouring projects",
|
|
369
|
+
"description": "List the other site sheets of the organization within a radius of this one, nearest first, with the distance, the geological unit their own scan established and whether it is the same as here, and the dossier that carries them with its counts of open and decided questions. This is what the public registers cannot say: the office already worked three hundred metres away. Nothing is interpolated: these are links to dossiers to reload, not values.",
|
|
370
|
+
"annotations": {
|
|
371
|
+
"readOnlyHint": true,
|
|
372
|
+
"destructiveHint": false,
|
|
373
|
+
"idempotentHint": true,
|
|
374
|
+
"openWorldHint": false
|
|
375
|
+
},
|
|
376
|
+
"transports": [
|
|
377
|
+
"stdio",
|
|
378
|
+
"remote"
|
|
379
|
+
],
|
|
380
|
+
"params": {
|
|
381
|
+
"siteId": "Site id from scan_site, list_sites or a dossier row.",
|
|
382
|
+
"radius": "How far to look, in metres, 50 to 5000. Default 500. At most twelve neighbours are returned."
|
|
383
|
+
}
|
|
384
|
+
},
|
|
255
385
|
{
|
|
256
386
|
"name": "list_dossiers",
|
|
257
387
|
"title": "Project dossiers",
|
|
@@ -517,6 +647,253 @@ export const CATALOG = [
|
|
|
517
647
|
"templateId": "The template, from list_templates."
|
|
518
648
|
}
|
|
519
649
|
},
|
|
650
|
+
{
|
|
651
|
+
"name": "list_questions",
|
|
652
|
+
"title": "Questions of a dossier",
|
|
653
|
+
"description": "List the questions of one dossier, one page at a time, with what the dossier page shows and load_dossier leaves out: status, assignee, due date, author, dates, the options with their ids and the title of the decision when there is one. Filter by status to read only what is still open. Use load_dossier to resume a project; use this to work through the questions one by one, then get_question on the one that matters. When nextCursor is present, call again with it as cursor.",
|
|
654
|
+
"annotations": {
|
|
655
|
+
"readOnlyHint": true,
|
|
656
|
+
"destructiveHint": false,
|
|
657
|
+
"idempotentHint": true,
|
|
658
|
+
"openWorldHint": false
|
|
659
|
+
},
|
|
660
|
+
"transports": [
|
|
661
|
+
"stdio",
|
|
662
|
+
"remote"
|
|
663
|
+
],
|
|
664
|
+
"params": {
|
|
665
|
+
"dossierId": "Dossier id from list_dossiers, open_dossier or load_dossier.",
|
|
666
|
+
"status": "open, decided or closed. Omit for all.",
|
|
667
|
+
"limit": "Questions per page, 1 to 200. Default 50.",
|
|
668
|
+
"cursor": "The nextCursor of the previous page."
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
"name": "get_question",
|
|
673
|
+
"title": "Read a question",
|
|
674
|
+
"description": "Read one question in full: its wording, status, assignee and due date, its options with their ids and descriptions, its decision, its evidence with every citation field (norm, section path, page, edition, attachment and page) and the option each piece argues for, and the comments left on the question and on those entries, each with its author. Evidence comes one page at a time; when nextCursor is present, call again with it as cursor. Call it before adding to a question, so nothing already filed is filed twice.",
|
|
675
|
+
"annotations": {
|
|
676
|
+
"readOnlyHint": true,
|
|
677
|
+
"destructiveHint": false,
|
|
678
|
+
"idempotentHint": true,
|
|
679
|
+
"openWorldHint": false
|
|
680
|
+
},
|
|
681
|
+
"transports": [
|
|
682
|
+
"stdio",
|
|
683
|
+
"remote"
|
|
684
|
+
],
|
|
685
|
+
"params": {
|
|
686
|
+
"questionId": "Question id from list_questions, load_dossier or open_question.",
|
|
687
|
+
"limit": "Evidence entries per page, 1 to 200. Default 50.",
|
|
688
|
+
"cursor": "The nextCursor of the previous page."
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"name": "get_dossier_activity",
|
|
693
|
+
"title": "Dossier history",
|
|
694
|
+
"description": "Read the history of a dossier, most recent first: who did what and when, from the app or from an agent, each line with the question or the entry it concerns. Call it when the user asks what changed since they last looked, or who took a decision. One page at a time; when nextCursor is present, call again with it as cursor. Lines are written in French at the time of the act, as the app shows them.",
|
|
695
|
+
"annotations": {
|
|
696
|
+
"readOnlyHint": true,
|
|
697
|
+
"destructiveHint": false,
|
|
698
|
+
"idempotentHint": true,
|
|
699
|
+
"openWorldHint": false
|
|
700
|
+
},
|
|
701
|
+
"transports": [
|
|
702
|
+
"stdio",
|
|
703
|
+
"remote"
|
|
704
|
+
],
|
|
705
|
+
"params": {
|
|
706
|
+
"dossierId": "Dossier id from list_dossiers, open_dossier or load_dossier.",
|
|
707
|
+
"limit": "Lines per page, 1 to 200. Default 50.",
|
|
708
|
+
"cursor": "The nextCursor of the previous page."
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
"name": "list_exports",
|
|
713
|
+
"title": "Dossier exports",
|
|
714
|
+
"description": "List the verification notes and journals exported from a dossier, most recent first, each with its kind, its SHA-256 hash, its size, the trusted timestamp when one was obtained, the methodology version in force and who exported it. The file itself is downloaded from the dossier page; this tells the user whether a note exists and lets them check a hash they were sent.",
|
|
715
|
+
"annotations": {
|
|
716
|
+
"readOnlyHint": true,
|
|
717
|
+
"destructiveHint": false,
|
|
718
|
+
"idempotentHint": true,
|
|
719
|
+
"openWorldHint": false
|
|
720
|
+
},
|
|
721
|
+
"transports": [
|
|
722
|
+
"stdio",
|
|
723
|
+
"remote"
|
|
724
|
+
],
|
|
725
|
+
"params": {
|
|
726
|
+
"dossierId": "Dossier id from list_dossiers, open_dossier or load_dossier."
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
"name": "update_question",
|
|
731
|
+
"title": "Edit a question",
|
|
732
|
+
"description": "Reword a question, rewrite what is at stake, assign it to a member of the organization by e-mail address, or set its due date. Pass only the fields to change; pass null to clear the assignee or the due date. Status changes go through record_decision and resolve_question, not here. Only when the user asked for the change.",
|
|
733
|
+
"annotations": {
|
|
734
|
+
"readOnlyHint": false,
|
|
735
|
+
"destructiveHint": false,
|
|
736
|
+
"idempotentHint": true,
|
|
737
|
+
"openWorldHint": false
|
|
738
|
+
},
|
|
739
|
+
"transports": [
|
|
740
|
+
"stdio",
|
|
741
|
+
"remote"
|
|
742
|
+
],
|
|
743
|
+
"params": {
|
|
744
|
+
"questionId": "Question id from list_questions, load_dossier or open_question.",
|
|
745
|
+
"title": "The new wording, in one line, phrased as a question.",
|
|
746
|
+
"body": "What is at stake and why it is not settled, in two or three sentences.",
|
|
747
|
+
"assigneeEmail": "E-mail address of the member to assign the question to. null removes the assignee.",
|
|
748
|
+
"dueAt": "Due date as an ISO day, e.g. \"2026-10-15\". null removes it."
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
"name": "add_option",
|
|
753
|
+
"title": "Add an option",
|
|
754
|
+
"description": "Add one way of settling a question, when a new variant comes up after the question was opened: \"keep the pile and test it\", \"redistribute on P37 and P39\". Idempotent on the name: the same words return the option already listed. Ten options per question at most. Returns optionId and created; the option is retained later by record_decision or update_option.",
|
|
755
|
+
"annotations": {
|
|
756
|
+
"readOnlyHint": false,
|
|
757
|
+
"destructiveHint": false,
|
|
758
|
+
"idempotentHint": true,
|
|
759
|
+
"openWorldHint": false
|
|
760
|
+
},
|
|
761
|
+
"transports": [
|
|
762
|
+
"stdio",
|
|
763
|
+
"remote"
|
|
764
|
+
],
|
|
765
|
+
"params": {
|
|
766
|
+
"questionId": "Question id from list_questions, load_dossier or open_question.",
|
|
767
|
+
"name": "The option in a few words, as it will be listed.",
|
|
768
|
+
"description": "What the option implies, in one or two sentences, when the name is not enough."
|
|
769
|
+
}
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
"name": "update_option",
|
|
773
|
+
"title": "Edit an option",
|
|
774
|
+
"description": "Rename or describe an option of a question, or mark it as the one retained. Retaining one option releases the others: a choice has one answer. Retaining here does not settle the question; call record_decision for that, which names the retained option itself. Pass only the fields to change. Only when the user asked for it.",
|
|
775
|
+
"annotations": {
|
|
776
|
+
"readOnlyHint": false,
|
|
777
|
+
"destructiveHint": false,
|
|
778
|
+
"idempotentHint": true,
|
|
779
|
+
"openWorldHint": false
|
|
780
|
+
},
|
|
781
|
+
"transports": [
|
|
782
|
+
"stdio",
|
|
783
|
+
"remote"
|
|
784
|
+
],
|
|
785
|
+
"params": {
|
|
786
|
+
"optionId": "Option id from get_question, list_questions or load_dossier.",
|
|
787
|
+
"name": "The new name of the option.",
|
|
788
|
+
"description": "The new description.",
|
|
789
|
+
"retained": "true to mark this option as retained (the others are released), false to release it."
|
|
790
|
+
}
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"name": "delete_option",
|
|
794
|
+
"title": "Remove an option",
|
|
795
|
+
"description": "Remove an option from a question. The evidence filed under it stays on the question, unfiled from the option. Irreversible: the user is asked to confirm through the client before anything is removed, unless confirmed is true because they already did in the conversation. Only when the user asked for it.",
|
|
796
|
+
"annotations": {
|
|
797
|
+
"readOnlyHint": false,
|
|
798
|
+
"destructiveHint": true,
|
|
799
|
+
"idempotentHint": false,
|
|
800
|
+
"openWorldHint": false
|
|
801
|
+
},
|
|
802
|
+
"transports": [
|
|
803
|
+
"stdio",
|
|
804
|
+
"remote"
|
|
805
|
+
],
|
|
806
|
+
"params": {
|
|
807
|
+
"optionId": "Option id from get_question, list_questions or load_dossier.",
|
|
808
|
+
"confirmed": "true when the user already confirmed the removal in the conversation. Otherwise the user is asked through the client first."
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
"name": "delete_question",
|
|
813
|
+
"title": "Delete a question",
|
|
814
|
+
"description": "Delete a question from a dossier. Its evidence stays in the dossier, unfiled; its options, its comments and its decision entry go with it. Irreversible: the user is asked to confirm through the client before anything is deleted, unless confirmed is true because they already did in the conversation. A question that stopped mattering is closed with resolve_question, not deleted; delete only a question opened by mistake, and only when the user says so.",
|
|
815
|
+
"annotations": {
|
|
816
|
+
"readOnlyHint": false,
|
|
817
|
+
"destructiveHint": true,
|
|
818
|
+
"idempotentHint": false,
|
|
819
|
+
"openWorldHint": false
|
|
820
|
+
},
|
|
821
|
+
"transports": [
|
|
822
|
+
"stdio",
|
|
823
|
+
"remote"
|
|
824
|
+
],
|
|
825
|
+
"params": {
|
|
826
|
+
"questionId": "Question id from list_questions, load_dossier or open_question.",
|
|
827
|
+
"confirmed": "true when the user already confirmed the deletion in the conversation. Otherwise the user is asked through the client first."
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
"name": "add_comment",
|
|
832
|
+
"title": "Leave a comment",
|
|
833
|
+
"description": "Leave a remark on a dossier, on one of its questions or on one entry: a doubt about a value, a note for a colleague, the reason a piece of evidence was set aside. A comment is signed by the connected user and is not evidence: what the norm says goes through save_finding. A signed-off dossier still takes comments. Write it in the user's own words, only when they asked to leave one.",
|
|
834
|
+
"annotations": {
|
|
835
|
+
"readOnlyHint": false,
|
|
836
|
+
"destructiveHint": false,
|
|
837
|
+
"idempotentHint": false,
|
|
838
|
+
"openWorldHint": false
|
|
839
|
+
},
|
|
840
|
+
"transports": [
|
|
841
|
+
"stdio",
|
|
842
|
+
"remote"
|
|
843
|
+
],
|
|
844
|
+
"params": {
|
|
845
|
+
"dossierId": "Dossier id from list_dossiers, open_dossier or load_dossier.",
|
|
846
|
+
"body": "The comment, one to a few sentences.",
|
|
847
|
+
"questionId": "The question the comment is about, when it is about one.",
|
|
848
|
+
"entryId": "The entry the comment is about, when it is about one."
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
"name": "update_entry",
|
|
853
|
+
"title": "Correct an entry",
|
|
854
|
+
"description": "Correct a piece of evidence or a decision in place: its wording, its value, its confidence, or the citation (norm, section path, page, edition) when the wrong clause was cited. Pass only the fields to change; pass page null to clear it. The kind and the question do not change here (attach_entry moves an entry). Only when the user asked for the correction; never rewrite what a colleague wrote without saying so.",
|
|
855
|
+
"annotations": {
|
|
856
|
+
"readOnlyHint": false,
|
|
857
|
+
"destructiveHint": false,
|
|
858
|
+
"idempotentHint": true,
|
|
859
|
+
"openWorldHint": false
|
|
860
|
+
},
|
|
861
|
+
"transports": [
|
|
862
|
+
"stdio",
|
|
863
|
+
"remote"
|
|
864
|
+
],
|
|
865
|
+
"params": {
|
|
866
|
+
"entryId": "Entry id from get_question or load_dossier.",
|
|
867
|
+
"title": "The fact in one line, as an engineer would write it in a report.",
|
|
868
|
+
"detail": "The reasoning in one or two sentences.",
|
|
869
|
+
"value": "The retained value with its unit, e.g. \"30 deg\".",
|
|
870
|
+
"confidence": "established, judgement or to_confirm.",
|
|
871
|
+
"normCode": "Norm the entry comes from, e.g. \"SIA 267\".",
|
|
872
|
+
"sectionPath": "Exact section path, e.g. \"9.5.2.1\".",
|
|
873
|
+
"page": "Page in the norm. null clears it.",
|
|
874
|
+
"normEdition": "The edition cited, e.g. \"2013\"."
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
"name": "attach_entry",
|
|
879
|
+
"title": "File an entry under a question",
|
|
880
|
+
"description": "File a piece of evidence under a question, and optionally under one of its options, or take it out with questionId null. This is how the unclassified evidence of load_dossier gets sorted: read it, find the question it answers, file it. A decision cannot be moved: it belongs to its question. Filing where it already is changes nothing.",
|
|
881
|
+
"annotations": {
|
|
882
|
+
"readOnlyHint": false,
|
|
883
|
+
"destructiveHint": false,
|
|
884
|
+
"idempotentHint": true,
|
|
885
|
+
"openWorldHint": false
|
|
886
|
+
},
|
|
887
|
+
"transports": [
|
|
888
|
+
"stdio",
|
|
889
|
+
"remote"
|
|
890
|
+
],
|
|
891
|
+
"params": {
|
|
892
|
+
"entryId": "Entry id from get_question or load_dossier.",
|
|
893
|
+
"questionId": "The question to file the entry under, or null to leave it unfiled.",
|
|
894
|
+
"optionId": "The option of that question the entry argues for, or null for none."
|
|
895
|
+
}
|
|
896
|
+
},
|
|
520
897
|
{
|
|
521
898
|
"name": "ingest_status",
|
|
522
899
|
"title": "Check ingestion status",
|
package/dist/tools/dossier.d.ts
CHANGED
|
@@ -82,6 +82,81 @@ export declare const applyTemplate: import("./define.js").ToolDef<{
|
|
|
82
82
|
dossierId: z.ZodString;
|
|
83
83
|
templateId: z.ZodString;
|
|
84
84
|
}>;
|
|
85
|
+
export declare const listQuestions: import("./define.js").ToolDef<{
|
|
86
|
+
dossierId: z.ZodString;
|
|
87
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
88
|
+
open: "open";
|
|
89
|
+
decided: "decided";
|
|
90
|
+
closed: "closed";
|
|
91
|
+
}>>;
|
|
92
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
93
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
94
|
+
}>;
|
|
95
|
+
export declare const getQuestion: import("./define.js").ToolDef<{
|
|
96
|
+
questionId: z.ZodString;
|
|
97
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
98
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
99
|
+
}>;
|
|
100
|
+
export declare const getDossierActivity: import("./define.js").ToolDef<{
|
|
101
|
+
dossierId: z.ZodString;
|
|
102
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
103
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
104
|
+
}>;
|
|
105
|
+
export declare const listExports: import("./define.js").ToolDef<{
|
|
106
|
+
dossierId: z.ZodString;
|
|
107
|
+
}>;
|
|
108
|
+
export declare const updateQuestion: import("./define.js").ToolDef<{
|
|
109
|
+
questionId: z.ZodString;
|
|
110
|
+
title: z.ZodOptional<z.ZodString>;
|
|
111
|
+
body: z.ZodOptional<z.ZodString>;
|
|
112
|
+
assigneeEmail: z.ZodOptional<z.ZodNullable<z.ZodEmail>>;
|
|
113
|
+
dueAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
114
|
+
}>;
|
|
115
|
+
export declare const addOption: import("./define.js").ToolDef<{
|
|
116
|
+
questionId: z.ZodString;
|
|
117
|
+
name: z.ZodString;
|
|
118
|
+
description: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}>;
|
|
120
|
+
export declare const updateOption: import("./define.js").ToolDef<{
|
|
121
|
+
optionId: z.ZodString;
|
|
122
|
+
name: z.ZodOptional<z.ZodString>;
|
|
123
|
+
description: z.ZodOptional<z.ZodString>;
|
|
124
|
+
retained: z.ZodOptional<z.ZodBoolean>;
|
|
125
|
+
}>;
|
|
126
|
+
export declare const deleteOption: import("./define.js").ToolDef<{
|
|
127
|
+
optionId: z.ZodString;
|
|
128
|
+
confirmed: z.ZodOptional<z.ZodBoolean>;
|
|
129
|
+
}>;
|
|
130
|
+
export declare const deleteQuestion: import("./define.js").ToolDef<{
|
|
131
|
+
questionId: z.ZodString;
|
|
132
|
+
confirmed: z.ZodOptional<z.ZodBoolean>;
|
|
133
|
+
}>;
|
|
134
|
+
export declare const addComment: import("./define.js").ToolDef<{
|
|
135
|
+
dossierId: z.ZodString;
|
|
136
|
+
body: z.ZodString;
|
|
137
|
+
questionId: z.ZodOptional<z.ZodString>;
|
|
138
|
+
entryId: z.ZodOptional<z.ZodString>;
|
|
139
|
+
}>;
|
|
140
|
+
export declare const updateEntry: import("./define.js").ToolDef<{
|
|
141
|
+
entryId: z.ZodString;
|
|
142
|
+
title: z.ZodOptional<z.ZodString>;
|
|
143
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
144
|
+
value: z.ZodOptional<z.ZodString>;
|
|
145
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
146
|
+
established: "established";
|
|
147
|
+
judgement: "judgement";
|
|
148
|
+
to_confirm: "to_confirm";
|
|
149
|
+
}>>;
|
|
150
|
+
normCode: z.ZodOptional<z.ZodString>;
|
|
151
|
+
sectionPath: z.ZodOptional<z.ZodString>;
|
|
152
|
+
page: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
153
|
+
normEdition: z.ZodOptional<z.ZodString>;
|
|
154
|
+
}>;
|
|
155
|
+
export declare const attachEntry: import("./define.js").ToolDef<{
|
|
156
|
+
entryId: z.ZodString;
|
|
157
|
+
questionId: z.ZodNullable<z.ZodString>;
|
|
158
|
+
optionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
159
|
+
}>;
|
|
85
160
|
export declare const dossierTools: (import("./define.js").ToolDef<{}> | import("./define.js").ToolDef<{
|
|
86
161
|
name: z.ZodString;
|
|
87
162
|
reference: z.ZodOptional<z.ZodString>;
|
|
@@ -152,4 +227,65 @@ export declare const dossierTools: (import("./define.js").ToolDef<{}> | import("
|
|
|
152
227
|
}> | import("./define.js").ToolDef<{
|
|
153
228
|
dossierId: z.ZodString;
|
|
154
229
|
templateId: z.ZodString;
|
|
230
|
+
}> | import("./define.js").ToolDef<{
|
|
231
|
+
dossierId: z.ZodString;
|
|
232
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
233
|
+
open: "open";
|
|
234
|
+
decided: "decided";
|
|
235
|
+
closed: "closed";
|
|
236
|
+
}>>;
|
|
237
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
238
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
239
|
+
}> | import("./define.js").ToolDef<{
|
|
240
|
+
questionId: z.ZodString;
|
|
241
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
242
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
243
|
+
}> | import("./define.js").ToolDef<{
|
|
244
|
+
dossierId: z.ZodString;
|
|
245
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
246
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
247
|
+
}> | import("./define.js").ToolDef<{
|
|
248
|
+
questionId: z.ZodString;
|
|
249
|
+
title: z.ZodOptional<z.ZodString>;
|
|
250
|
+
body: z.ZodOptional<z.ZodString>;
|
|
251
|
+
assigneeEmail: z.ZodOptional<z.ZodNullable<z.ZodEmail>>;
|
|
252
|
+
dueAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
253
|
+
}> | import("./define.js").ToolDef<{
|
|
254
|
+
questionId: z.ZodString;
|
|
255
|
+
name: z.ZodString;
|
|
256
|
+
description: z.ZodOptional<z.ZodString>;
|
|
257
|
+
}> | import("./define.js").ToolDef<{
|
|
258
|
+
optionId: z.ZodString;
|
|
259
|
+
name: z.ZodOptional<z.ZodString>;
|
|
260
|
+
description: z.ZodOptional<z.ZodString>;
|
|
261
|
+
retained: z.ZodOptional<z.ZodBoolean>;
|
|
262
|
+
}> | import("./define.js").ToolDef<{
|
|
263
|
+
optionId: z.ZodString;
|
|
264
|
+
confirmed: z.ZodOptional<z.ZodBoolean>;
|
|
265
|
+
}> | import("./define.js").ToolDef<{
|
|
266
|
+
questionId: z.ZodString;
|
|
267
|
+
confirmed: z.ZodOptional<z.ZodBoolean>;
|
|
268
|
+
}> | import("./define.js").ToolDef<{
|
|
269
|
+
dossierId: z.ZodString;
|
|
270
|
+
body: z.ZodString;
|
|
271
|
+
questionId: z.ZodOptional<z.ZodString>;
|
|
272
|
+
entryId: z.ZodOptional<z.ZodString>;
|
|
273
|
+
}> | import("./define.js").ToolDef<{
|
|
274
|
+
entryId: z.ZodString;
|
|
275
|
+
title: z.ZodOptional<z.ZodString>;
|
|
276
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
277
|
+
value: z.ZodOptional<z.ZodString>;
|
|
278
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
279
|
+
established: "established";
|
|
280
|
+
judgement: "judgement";
|
|
281
|
+
to_confirm: "to_confirm";
|
|
282
|
+
}>>;
|
|
283
|
+
normCode: z.ZodOptional<z.ZodString>;
|
|
284
|
+
sectionPath: z.ZodOptional<z.ZodString>;
|
|
285
|
+
page: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
286
|
+
normEdition: z.ZodOptional<z.ZodString>;
|
|
287
|
+
}> | import("./define.js").ToolDef<{
|
|
288
|
+
entryId: z.ZodString;
|
|
289
|
+
questionId: z.ZodNullable<z.ZodString>;
|
|
290
|
+
optionId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
155
291
|
}>)[];
|
package/dist/tools/dossier.js
CHANGED
|
@@ -358,6 +358,276 @@ export const applyTemplate = defineTool({
|
|
|
358
358
|
templateId: args.templateId,
|
|
359
359
|
}),
|
|
360
360
|
});
|
|
361
|
+
/* ------------------------------------------------- questions (0.14.0) */
|
|
362
|
+
//
|
|
363
|
+
// Everything the dossier page can read and do to a question (ADR 36). The
|
|
364
|
+
// reads paginate with `cursor`; the two deletions go through the same
|
|
365
|
+
// confirmation gate as `record_decision` (`confirm.ts`), and `confirmed` is
|
|
366
|
+
// read there, never sent.
|
|
367
|
+
const questionStatus = z.enum(['open', 'decided', 'closed']);
|
|
368
|
+
const cursor = (tool) => z.string().min(1).optional().describe(param(tool, 'cursor'));
|
|
369
|
+
const pageLimit = (tool) => z.number().int().min(1).max(200).optional().describe(param(tool, 'limit'));
|
|
370
|
+
export const listQuestions = defineTool({
|
|
371
|
+
...headOf('list_questions'),
|
|
372
|
+
inputSchema: {
|
|
373
|
+
dossierId: dossierId('list_questions'),
|
|
374
|
+
status: questionStatus
|
|
375
|
+
.optional()
|
|
376
|
+
.describe(param('list_questions', 'status')),
|
|
377
|
+
limit: pageLimit('list_questions'),
|
|
378
|
+
cursor: cursor('list_questions'),
|
|
379
|
+
},
|
|
380
|
+
run: (client, args) => client.action(api.dossiersApi.listQuestions, {
|
|
381
|
+
apiKey: requireApiKey(),
|
|
382
|
+
dossierId: args.dossierId,
|
|
383
|
+
status: args.status,
|
|
384
|
+
limit: args.limit,
|
|
385
|
+
cursor: args.cursor,
|
|
386
|
+
}),
|
|
387
|
+
});
|
|
388
|
+
export const getQuestion = defineTool({
|
|
389
|
+
...headOf('get_question'),
|
|
390
|
+
inputSchema: {
|
|
391
|
+
questionId: questionId('get_question'),
|
|
392
|
+
limit: pageLimit('get_question'),
|
|
393
|
+
cursor: cursor('get_question'),
|
|
394
|
+
},
|
|
395
|
+
run: (client, args) => client.action(api.dossiersApi.getQuestion, {
|
|
396
|
+
apiKey: requireApiKey(),
|
|
397
|
+
questionId: args.questionId,
|
|
398
|
+
limit: args.limit,
|
|
399
|
+
cursor: args.cursor,
|
|
400
|
+
}),
|
|
401
|
+
});
|
|
402
|
+
export const getDossierActivity = defineTool({
|
|
403
|
+
...headOf('get_dossier_activity'),
|
|
404
|
+
inputSchema: {
|
|
405
|
+
dossierId: dossierId('get_dossier_activity'),
|
|
406
|
+
limit: pageLimit('get_dossier_activity'),
|
|
407
|
+
cursor: cursor('get_dossier_activity'),
|
|
408
|
+
},
|
|
409
|
+
run: (client, args) => client.action(api.dossiersApi.getDossierActivity, {
|
|
410
|
+
apiKey: requireApiKey(),
|
|
411
|
+
dossierId: args.dossierId,
|
|
412
|
+
limit: args.limit,
|
|
413
|
+
cursor: args.cursor,
|
|
414
|
+
}),
|
|
415
|
+
});
|
|
416
|
+
export const listExports = defineTool({
|
|
417
|
+
...headOf('list_exports'),
|
|
418
|
+
inputSchema: { dossierId: dossierId('list_exports') },
|
|
419
|
+
run: (client, args) => client.action(api.dossiersApi.listExports, {
|
|
420
|
+
apiKey: requireApiKey(),
|
|
421
|
+
dossierId: args.dossierId,
|
|
422
|
+
}),
|
|
423
|
+
});
|
|
424
|
+
export const updateQuestion = defineTool({
|
|
425
|
+
...headOf('update_question'),
|
|
426
|
+
inputSchema: {
|
|
427
|
+
questionId: questionId('update_question'),
|
|
428
|
+
title: z
|
|
429
|
+
.string()
|
|
430
|
+
.min(1)
|
|
431
|
+
.max(200)
|
|
432
|
+
.optional()
|
|
433
|
+
.describe(param('update_question', 'title')),
|
|
434
|
+
body: z
|
|
435
|
+
.string()
|
|
436
|
+
.max(4000)
|
|
437
|
+
.optional()
|
|
438
|
+
.describe(param('update_question', 'body')),
|
|
439
|
+
assigneeEmail: z
|
|
440
|
+
.email()
|
|
441
|
+
.nullable()
|
|
442
|
+
.optional()
|
|
443
|
+
.describe(param('update_question', 'assigneeEmail')),
|
|
444
|
+
dueAt: z
|
|
445
|
+
.string()
|
|
446
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
447
|
+
.nullable()
|
|
448
|
+
.optional()
|
|
449
|
+
.describe(param('update_question', 'dueAt')),
|
|
450
|
+
},
|
|
451
|
+
run: (client, args) => client.action(api.dossiersApi.updateQuestion, {
|
|
452
|
+
apiKey: requireApiKey(),
|
|
453
|
+
questionId: args.questionId,
|
|
454
|
+
title: args.title,
|
|
455
|
+
body: args.body,
|
|
456
|
+
assigneeEmail: args.assigneeEmail,
|
|
457
|
+
dueAt: args.dueAt,
|
|
458
|
+
}),
|
|
459
|
+
});
|
|
460
|
+
export const addOption = defineTool({
|
|
461
|
+
...headOf('add_option'),
|
|
462
|
+
inputSchema: {
|
|
463
|
+
questionId: questionId('add_option'),
|
|
464
|
+
name: z.string().min(1).max(120).describe(param('add_option', 'name')),
|
|
465
|
+
description: z
|
|
466
|
+
.string()
|
|
467
|
+
.max(2000)
|
|
468
|
+
.optional()
|
|
469
|
+
.describe(param('add_option', 'description')),
|
|
470
|
+
},
|
|
471
|
+
run: (client, args) => client.action(api.dossiersApi.addOption, {
|
|
472
|
+
apiKey: requireApiKey(),
|
|
473
|
+
questionId: args.questionId,
|
|
474
|
+
name: args.name,
|
|
475
|
+
description: args.description,
|
|
476
|
+
}),
|
|
477
|
+
});
|
|
478
|
+
const optionId = (tool) => z.string().min(1).describe(param(tool, 'optionId'));
|
|
479
|
+
export const updateOption = defineTool({
|
|
480
|
+
...headOf('update_option'),
|
|
481
|
+
inputSchema: {
|
|
482
|
+
optionId: optionId('update_option'),
|
|
483
|
+
name: z
|
|
484
|
+
.string()
|
|
485
|
+
.min(1)
|
|
486
|
+
.max(120)
|
|
487
|
+
.optional()
|
|
488
|
+
.describe(param('update_option', 'name')),
|
|
489
|
+
description: z
|
|
490
|
+
.string()
|
|
491
|
+
.max(2000)
|
|
492
|
+
.optional()
|
|
493
|
+
.describe(param('update_option', 'description')),
|
|
494
|
+
retained: z
|
|
495
|
+
.boolean()
|
|
496
|
+
.optional()
|
|
497
|
+
.describe(param('update_option', 'retained')),
|
|
498
|
+
},
|
|
499
|
+
run: (client, args) => client.action(api.dossiersApi.updateOption, {
|
|
500
|
+
apiKey: requireApiKey(),
|
|
501
|
+
optionId: args.optionId,
|
|
502
|
+
name: args.name,
|
|
503
|
+
description: args.description,
|
|
504
|
+
retained: args.retained,
|
|
505
|
+
}),
|
|
506
|
+
});
|
|
507
|
+
export const deleteOption = defineTool({
|
|
508
|
+
...headOf('delete_option'),
|
|
509
|
+
inputSchema: {
|
|
510
|
+
optionId: optionId('delete_option'),
|
|
511
|
+
confirmed: z
|
|
512
|
+
.boolean()
|
|
513
|
+
.optional()
|
|
514
|
+
.describe(param('delete_option', 'confirmed')),
|
|
515
|
+
},
|
|
516
|
+
run: (client, { confirmed: _confirmed, ...args }) => client.action(api.dossiersApi.deleteOption, {
|
|
517
|
+
apiKey: requireApiKey(),
|
|
518
|
+
optionId: args.optionId,
|
|
519
|
+
}),
|
|
520
|
+
});
|
|
521
|
+
export const deleteQuestion = defineTool({
|
|
522
|
+
...headOf('delete_question'),
|
|
523
|
+
inputSchema: {
|
|
524
|
+
questionId: questionId('delete_question'),
|
|
525
|
+
confirmed: z
|
|
526
|
+
.boolean()
|
|
527
|
+
.optional()
|
|
528
|
+
.describe(param('delete_question', 'confirmed')),
|
|
529
|
+
},
|
|
530
|
+
run: (client, { confirmed: _confirmed, ...args }) => client.action(api.dossiersApi.deleteQuestion, {
|
|
531
|
+
apiKey: requireApiKey(),
|
|
532
|
+
questionId: args.questionId,
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
export const addComment = defineTool({
|
|
536
|
+
...headOf('add_comment'),
|
|
537
|
+
inputSchema: {
|
|
538
|
+
dossierId: dossierId('add_comment'),
|
|
539
|
+
body: z.string().min(1).max(4000).describe(param('add_comment', 'body')),
|
|
540
|
+
questionId: questionId('add_comment').optional(),
|
|
541
|
+
entryId: z
|
|
542
|
+
.string()
|
|
543
|
+
.min(1)
|
|
544
|
+
.optional()
|
|
545
|
+
.describe(param('add_comment', 'entryId')),
|
|
546
|
+
},
|
|
547
|
+
run: (client, args) => client.action(api.dossiersApi.addComment, {
|
|
548
|
+
apiKey: requireApiKey(),
|
|
549
|
+
dossierId: args.dossierId,
|
|
550
|
+
body: args.body,
|
|
551
|
+
questionId: args.questionId,
|
|
552
|
+
entryId: args.entryId,
|
|
553
|
+
}),
|
|
554
|
+
});
|
|
555
|
+
export const updateEntry = defineTool({
|
|
556
|
+
...headOf('update_entry'),
|
|
557
|
+
inputSchema: {
|
|
558
|
+
entryId: z.string().min(1).describe(param('update_entry', 'entryId')),
|
|
559
|
+
title: z
|
|
560
|
+
.string()
|
|
561
|
+
.min(1)
|
|
562
|
+
.max(200)
|
|
563
|
+
.optional()
|
|
564
|
+
.describe(param('update_entry', 'title')),
|
|
565
|
+
detail: z
|
|
566
|
+
.string()
|
|
567
|
+
.max(4000)
|
|
568
|
+
.optional()
|
|
569
|
+
.describe(param('update_entry', 'detail')),
|
|
570
|
+
value: z
|
|
571
|
+
.string()
|
|
572
|
+
.max(120)
|
|
573
|
+
.optional()
|
|
574
|
+
.describe(param('update_entry', 'value')),
|
|
575
|
+
confidence: z
|
|
576
|
+
.enum(['established', 'judgement', 'to_confirm'])
|
|
577
|
+
.optional()
|
|
578
|
+
.describe(param('update_entry', 'confidence')),
|
|
579
|
+
normCode: z
|
|
580
|
+
.string()
|
|
581
|
+
.max(40)
|
|
582
|
+
.optional()
|
|
583
|
+
.describe(param('update_entry', 'normCode')),
|
|
584
|
+
sectionPath: z
|
|
585
|
+
.string()
|
|
586
|
+
.max(60)
|
|
587
|
+
.optional()
|
|
588
|
+
.describe(param('update_entry', 'sectionPath')),
|
|
589
|
+
page: z
|
|
590
|
+
.number()
|
|
591
|
+
.int()
|
|
592
|
+
.positive()
|
|
593
|
+
.nullable()
|
|
594
|
+
.optional()
|
|
595
|
+
.describe(param('update_entry', 'page')),
|
|
596
|
+
normEdition: z
|
|
597
|
+
.string()
|
|
598
|
+
.max(40)
|
|
599
|
+
.optional()
|
|
600
|
+
.describe(param('update_entry', 'normEdition')),
|
|
601
|
+
},
|
|
602
|
+
run: (client, args) => client.action(api.dossiersApi.updateEntry, {
|
|
603
|
+
apiKey: requireApiKey(),
|
|
604
|
+
...args,
|
|
605
|
+
entryId: args.entryId,
|
|
606
|
+
}),
|
|
607
|
+
});
|
|
608
|
+
export const attachEntry = defineTool({
|
|
609
|
+
...headOf('attach_entry'),
|
|
610
|
+
inputSchema: {
|
|
611
|
+
entryId: z.string().min(1).describe(param('attach_entry', 'entryId')),
|
|
612
|
+
questionId: z
|
|
613
|
+
.string()
|
|
614
|
+
.min(1)
|
|
615
|
+
.nullable()
|
|
616
|
+
.describe(param('attach_entry', 'questionId')),
|
|
617
|
+
optionId: z
|
|
618
|
+
.string()
|
|
619
|
+
.min(1)
|
|
620
|
+
.nullable()
|
|
621
|
+
.optional()
|
|
622
|
+
.describe(param('attach_entry', 'optionId')),
|
|
623
|
+
},
|
|
624
|
+
run: (client, args) => client.action(api.dossiersApi.attachEntry, {
|
|
625
|
+
apiKey: requireApiKey(),
|
|
626
|
+
entryId: args.entryId,
|
|
627
|
+
questionId: args.questionId,
|
|
628
|
+
optionId: args.optionId,
|
|
629
|
+
}),
|
|
630
|
+
});
|
|
361
631
|
export const dossierTools = [
|
|
362
632
|
listDossiers,
|
|
363
633
|
openDossier,
|
|
@@ -372,4 +642,16 @@ export const dossierTools = [
|
|
|
372
642
|
addAttachment,
|
|
373
643
|
listTemplates,
|
|
374
644
|
applyTemplate,
|
|
645
|
+
listQuestions,
|
|
646
|
+
getQuestion,
|
|
647
|
+
getDossierActivity,
|
|
648
|
+
listExports,
|
|
649
|
+
updateQuestion,
|
|
650
|
+
addOption,
|
|
651
|
+
updateOption,
|
|
652
|
+
deleteOption,
|
|
653
|
+
deleteQuestion,
|
|
654
|
+
addComment,
|
|
655
|
+
updateEntry,
|
|
656
|
+
attachEntry,
|
|
375
657
|
];
|
package/dist/tools/site.d.ts
CHANGED
|
@@ -30,6 +30,41 @@ export declare const getBoreholes: import("./define.js").ToolDef<{
|
|
|
30
30
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
31
31
|
withStrataOnly: z.ZodOptional<z.ZodBoolean>;
|
|
32
32
|
}>;
|
|
33
|
+
/**
|
|
34
|
+
* The Site tab of a dossier, read by an agent (0.14.0, ADR 36).
|
|
35
|
+
*
|
|
36
|
+
* `get_site_context` is the summary shaped for an answer; these are the
|
|
37
|
+
* record: every fact with its key and notice, the section along the axis,
|
|
38
|
+
* the map areas, the piezometric contours, the photos, the neighbouring
|
|
39
|
+
* projects, and the list of sheets. Geometry is left out unless asked for:
|
|
40
|
+
* a water protection sector runs to hundreds of vertices, and an agent
|
|
41
|
+
* reads distances, not polygons.
|
|
42
|
+
*/
|
|
43
|
+
export declare const listSites: import("./define.js").ToolDef<{
|
|
44
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
}>;
|
|
46
|
+
export declare const getSite: import("./define.js").ToolDef<{
|
|
47
|
+
siteId: z.ZodString;
|
|
48
|
+
}>;
|
|
49
|
+
export declare const getSiteSection: import("./define.js").ToolDef<{
|
|
50
|
+
siteId: z.ZodString;
|
|
51
|
+
maxPoints: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
}>;
|
|
53
|
+
export declare const listSiteOverlays: import("./define.js").ToolDef<{
|
|
54
|
+
siteId: z.ZodString;
|
|
55
|
+
includeGeometry: z.ZodOptional<z.ZodBoolean>;
|
|
56
|
+
}>;
|
|
57
|
+
export declare const getGroundwaterContours: import("./define.js").ToolDef<{
|
|
58
|
+
siteId: z.ZodString;
|
|
59
|
+
includeGeometry: z.ZodOptional<z.ZodBoolean>;
|
|
60
|
+
}>;
|
|
61
|
+
export declare const listSitePhotos: import("./define.js").ToolDef<{
|
|
62
|
+
siteId: z.ZodString;
|
|
63
|
+
}>;
|
|
64
|
+
export declare const listSiteNeighbours: import("./define.js").ToolDef<{
|
|
65
|
+
siteId: z.ZodString;
|
|
66
|
+
radius: z.ZodOptional<z.ZodNumber>;
|
|
67
|
+
}>;
|
|
33
68
|
export declare const siteTools: (import("./define.js").ToolDef<{
|
|
34
69
|
dossierId: z.ZodString;
|
|
35
70
|
address: z.ZodString;
|
|
@@ -50,4 +85,15 @@ export declare const siteTools: (import("./define.js").ToolDef<{
|
|
|
50
85
|
*/
|
|
51
86
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
52
87
|
withStrataOnly: z.ZodOptional<z.ZodBoolean>;
|
|
88
|
+
}> | import("./define.js").ToolDef<{
|
|
89
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
90
|
+
}> | import("./define.js").ToolDef<{
|
|
91
|
+
siteId: z.ZodString;
|
|
92
|
+
maxPoints: z.ZodOptional<z.ZodNumber>;
|
|
93
|
+
}> | import("./define.js").ToolDef<{
|
|
94
|
+
siteId: z.ZodString;
|
|
95
|
+
includeGeometry: z.ZodOptional<z.ZodBoolean>;
|
|
96
|
+
}> | import("./define.js").ToolDef<{
|
|
97
|
+
siteId: z.ZodString;
|
|
98
|
+
radius: z.ZodOptional<z.ZodNumber>;
|
|
53
99
|
}>)[];
|
package/dist/tools/site.js
CHANGED
|
@@ -97,4 +97,124 @@ export const getBoreholes = defineTool({
|
|
|
97
97
|
withStrataOnly: args.withStrataOnly,
|
|
98
98
|
}),
|
|
99
99
|
});
|
|
100
|
-
|
|
100
|
+
const siteId = (tool) => z.string().min(1).describe(param(tool, 'siteId'));
|
|
101
|
+
/**
|
|
102
|
+
* The Site tab of a dossier, read by an agent (0.14.0, ADR 36).
|
|
103
|
+
*
|
|
104
|
+
* `get_site_context` is the summary shaped for an answer; these are the
|
|
105
|
+
* record: every fact with its key and notice, the section along the axis,
|
|
106
|
+
* the map areas, the piezometric contours, the photos, the neighbouring
|
|
107
|
+
* projects, and the list of sheets. Geometry is left out unless asked for:
|
|
108
|
+
* a water protection sector runs to hundreds of vertices, and an agent
|
|
109
|
+
* reads distances, not polygons.
|
|
110
|
+
*/
|
|
111
|
+
export const listSites = defineTool({
|
|
112
|
+
...headOf('list_sites'),
|
|
113
|
+
inputSchema: {
|
|
114
|
+
limit: z
|
|
115
|
+
.number()
|
|
116
|
+
.int()
|
|
117
|
+
.min(1)
|
|
118
|
+
.max(200)
|
|
119
|
+
.optional()
|
|
120
|
+
.describe(param('list_sites', 'limit')),
|
|
121
|
+
},
|
|
122
|
+
run: (client, args) => client.action(api.sitesApi.listSites, {
|
|
123
|
+
apiKey: requireApiKey(),
|
|
124
|
+
limit: args.limit,
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
export const getSite = defineTool({
|
|
128
|
+
...headOf('get_site'),
|
|
129
|
+
inputSchema: { siteId: siteId('get_site') },
|
|
130
|
+
run: (client, args) => client.action(api.sitesApi.getSite, {
|
|
131
|
+
apiKey: requireApiKey(),
|
|
132
|
+
siteId: args.siteId,
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
export const getSiteSection = defineTool({
|
|
136
|
+
...headOf('get_site_section'),
|
|
137
|
+
inputSchema: {
|
|
138
|
+
siteId: siteId('get_site_section'),
|
|
139
|
+
maxPoints: z
|
|
140
|
+
.number()
|
|
141
|
+
.int()
|
|
142
|
+
.min(2)
|
|
143
|
+
.max(200)
|
|
144
|
+
.optional()
|
|
145
|
+
.describe(param('get_site_section', 'maxPoints')),
|
|
146
|
+
},
|
|
147
|
+
run: (client, args) => client.action(api.sitesApi.getSiteSection, {
|
|
148
|
+
apiKey: requireApiKey(),
|
|
149
|
+
siteId: args.siteId,
|
|
150
|
+
maxPoints: args.maxPoints,
|
|
151
|
+
}),
|
|
152
|
+
});
|
|
153
|
+
export const listSiteOverlays = defineTool({
|
|
154
|
+
...headOf('list_site_overlays'),
|
|
155
|
+
inputSchema: {
|
|
156
|
+
siteId: siteId('list_site_overlays'),
|
|
157
|
+
includeGeometry: z
|
|
158
|
+
.boolean()
|
|
159
|
+
.optional()
|
|
160
|
+
.describe(param('list_site_overlays', 'includeGeometry')),
|
|
161
|
+
},
|
|
162
|
+
run: (client, args) => client.action(api.sitesApi.listSiteOverlays, {
|
|
163
|
+
apiKey: requireApiKey(),
|
|
164
|
+
siteId: args.siteId,
|
|
165
|
+
includeGeometry: args.includeGeometry,
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
export const getGroundwaterContours = defineTool({
|
|
169
|
+
...headOf('get_groundwater_contours'),
|
|
170
|
+
inputSchema: {
|
|
171
|
+
siteId: siteId('get_groundwater_contours'),
|
|
172
|
+
includeGeometry: z
|
|
173
|
+
.boolean()
|
|
174
|
+
.optional()
|
|
175
|
+
.describe(param('get_groundwater_contours', 'includeGeometry')),
|
|
176
|
+
},
|
|
177
|
+
run: (client, args) => client.action(api.sitesApi.getGroundwaterContours, {
|
|
178
|
+
apiKey: requireApiKey(),
|
|
179
|
+
siteId: args.siteId,
|
|
180
|
+
includeGeometry: args.includeGeometry,
|
|
181
|
+
}),
|
|
182
|
+
});
|
|
183
|
+
export const listSitePhotos = defineTool({
|
|
184
|
+
...headOf('list_site_photos'),
|
|
185
|
+
inputSchema: { siteId: siteId('list_site_photos') },
|
|
186
|
+
run: (client, args) => client.action(api.sitesApi.listSitePhotos, {
|
|
187
|
+
apiKey: requireApiKey(),
|
|
188
|
+
siteId: args.siteId,
|
|
189
|
+
}),
|
|
190
|
+
});
|
|
191
|
+
export const listSiteNeighbours = defineTool({
|
|
192
|
+
...headOf('list_site_neighbours'),
|
|
193
|
+
inputSchema: {
|
|
194
|
+
siteId: siteId('list_site_neighbours'),
|
|
195
|
+
radius: z
|
|
196
|
+
.number()
|
|
197
|
+
.int()
|
|
198
|
+
.min(50)
|
|
199
|
+
.max(5000)
|
|
200
|
+
.optional()
|
|
201
|
+
.describe(param('list_site_neighbours', 'radius')),
|
|
202
|
+
},
|
|
203
|
+
run: (client, args) => client.action(api.sitesApi.listSiteNeighbours, {
|
|
204
|
+
apiKey: requireApiKey(),
|
|
205
|
+
siteId: args.siteId,
|
|
206
|
+
radius: args.radius,
|
|
207
|
+
}),
|
|
208
|
+
});
|
|
209
|
+
export const siteTools = [
|
|
210
|
+
scanSite,
|
|
211
|
+
getSiteContext,
|
|
212
|
+
getBoreholes,
|
|
213
|
+
listSites,
|
|
214
|
+
getSite,
|
|
215
|
+
getSiteSection,
|
|
216
|
+
listSiteOverlays,
|
|
217
|
+
getGroundwaterContours,
|
|
218
|
+
listSitePhotos,
|
|
219
|
+
listSiteNeighbours,
|
|
220
|
+
];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratta/mcp",
|
|
3
3
|
"mcpName": "ch.stratta/mcp",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
5
5
|
"description": "MCP server exposing the engineering norms your firm is licensed for (SIA / Eurocodes) to any MCP client, via Stratta TreeRAG.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"author": "SmartFlow <hello@stratta.ch>",
|
|
@@ -46,7 +46,7 @@ A conversation disappears, a project lasts months. The dossier is what remains:
|
|
|
46
46
|
|
|
47
47
|
**Open one** (`open_dossier`) when the user names a project, a structure, a site or a mandate, when a value is retained for a design rather than looked up, when a hypothesis is set, when a site observation is reported, or when a question is left open. Do not open a dossier for a one-off lookup with no project behind it.
|
|
48
48
|
|
|
49
|
-
**Reload it first** (`list_dossiers`, `load_dossier`) BEFORE answering, as soon as the user returns to a project already named ("pick up dossier X", "where were we on Y"): reloading is what stops a decision already taken from being taken again. Read its entries and its open questions before answering anything about that project.
|
|
49
|
+
**Reload it first** (`list_dossiers`, `load_dossier`) BEFORE answering, as soon as the user returns to a project already named ("pick up dossier X", "where were we on Y"): reloading is what stops a decision already taken from being taken again. Read its entries and its open questions before answering anything about that project. To work on one question, `get_question` reads it in full (options, evidence with every citation field, comments); `attach_entry` files what `load_dossier` lists as unclassified. A question is edited with `update_question`, never deleted unless the user says so.
|
|
50
50
|
|
|
51
51
|
**Read its attachments.** A dossier carries the project's own documents (site reports, borehole logs, meeting minutes): `list_attachments`, then `read_attachment` on what bears on the question, or `search_in_dossier` when the dossier holds many. A fact from a piece is evidence like a clause: cite it as [name, p. N] and file it with `attachmentId` and `attachmentPage`.
|
|
52
52
|
|