@stratta/mcp 0.9.8 → 0.12.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 -11
- package/dist/confirm.d.ts +15 -0
- package/dist/confirm.js +54 -0
- package/dist/errors.js +27 -0
- package/dist/index.js +27 -2
- package/dist/prompts.d.ts +4 -0
- package/dist/prompts.js +40 -0
- package/dist/resources.d.ts +3 -0
- package/dist/resources.js +35 -0
- package/dist/tools/catalog.gen.d.ts +34 -0
- package/dist/tools/catalog.gen.js +724 -0
- package/dist/tools/dossier.d.ts +96 -4
- package/dist/tools/dossier.js +291 -90
- package/dist/tools/ingest.d.ts +8 -0
- package/dist/tools/ingest.js +116 -98
- package/dist/tools/read.d.ts +42 -17
- package/dist/tools/read.js +160 -84
- package/dist/usage.d.ts +3 -0
- package/dist/usage.js +50 -0
- package/package.json +1 -1
- package/scripts/ingest-prepass.py +499 -54
- package/scripts/tests/test_prepass.py +211 -0
- package/skills/consult-stratta/SKILL.md +73 -0
- package/skills/ingest-norm/SKILL.md +99 -44
- package/skills/verification-note/SKILL.md +54 -0
package/dist/tools/ingest.js
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { api } from '../client.js';
|
|
3
3
|
import { requireApiKey } from '../auth.js';
|
|
4
|
+
import { catalogEntry, param } from './catalog.gen.js';
|
|
4
5
|
import { defineTool } from './define.js';
|
|
5
6
|
/**
|
|
6
|
-
* Ingestion tools
|
|
7
|
-
* its Stratta workspace,
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Ingestion tools: let an engineering office add its own licensed norms to
|
|
8
|
+
* its Stratta workspace, from the user's own agent. Every call is
|
|
9
|
+
* authenticated by the user's API key and scoped server-side to their
|
|
10
|
+
* organisation (see convex/ingestionApi.ts). Driven by the `ingest-norm`
|
|
11
|
+
* skill. Absent from the remote transport on purpose: the pipeline starts
|
|
12
|
+
* with a PDF on the caller's disk.
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* SDK before the handler is entered, so a bad call fails at the boundary with
|
|
16
|
-
* a message naming the field.
|
|
14
|
+
* Names, descriptions and annotations come from the generated catalogue. The
|
|
15
|
+
* Zod shapes below are enforced by the SDK before a handler runs, so a bad
|
|
16
|
+
* call fails at the boundary with a message naming the field, not deep inside
|
|
17
|
+
* Convex.
|
|
17
18
|
*/
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const headOf = (name) => {
|
|
20
|
+
const entry = catalogEntry(name);
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
title: entry.title,
|
|
24
|
+
description: entry.description,
|
|
25
|
+
annotations: entry.annotations,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const documentId = (tool) => z.string().min(1).describe(param(tool, 'documentId'));
|
|
29
|
+
const sectionId = (tool) => z.string().min(1).describe(param(tool, 'sectionId'));
|
|
26
30
|
const sectionInput = z.object({
|
|
27
31
|
nodeId: z
|
|
28
32
|
.string()
|
|
@@ -46,33 +50,46 @@ const sectionInput = z.object({
|
|
|
46
50
|
pageEnd: z.number().int().min(0),
|
|
47
51
|
orderIndex: z.number().int().min(0),
|
|
48
52
|
});
|
|
49
|
-
/** Writes: not read-only, and re-running one is not automatically safe. */
|
|
50
|
-
const write = { readOnlyHint: false, openWorldHint: false };
|
|
51
53
|
export const ingestStatus = defineTool({
|
|
52
|
-
|
|
53
|
-
title: 'Check ingestion status',
|
|
54
|
-
description: 'Check whether a norm (by code) already exists in YOUR workspace and how many sections it has. Call before creating to avoid duplicates.',
|
|
54
|
+
...headOf('ingest_status'),
|
|
55
55
|
inputSchema: {
|
|
56
|
-
code: z.string().min(1).describe('
|
|
56
|
+
code: z.string().min(1).describe(param('ingest_status', 'code')),
|
|
57
57
|
},
|
|
58
|
-
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
59
58
|
run: (client, args) => client.action(api.ingestionApi.ingestStatus, {
|
|
60
59
|
apiKey: requireApiKey(),
|
|
61
60
|
code: args.code,
|
|
62
61
|
}),
|
|
63
62
|
});
|
|
64
63
|
export const ingestCreateDocument = defineTool({
|
|
65
|
-
|
|
66
|
-
title: 'Create norm document',
|
|
67
|
-
description: 'Create a draft norm document in YOUR workspace. Returns the documentId used by subsequent ingest_* calls. You must hold a valid licence for the norm you ingest.',
|
|
64
|
+
...headOf('ingest_create_document'),
|
|
68
65
|
inputSchema: {
|
|
69
|
-
code: z.string().min(1),
|
|
70
|
-
year: z
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
code: z.string().min(1).describe(param('ingest_create_document', 'code')),
|
|
67
|
+
year: z
|
|
68
|
+
.number()
|
|
69
|
+
.int()
|
|
70
|
+
.min(1900)
|
|
71
|
+
.max(2100)
|
|
72
|
+
.describe(param('ingest_create_document', 'year')),
|
|
73
|
+
title: z.string().min(1).describe(param('ingest_create_document', 'title')),
|
|
74
|
+
language: z
|
|
75
|
+
.enum(['fr', 'de', 'it', 'en'])
|
|
76
|
+
.describe(param('ingest_create_document', 'language')),
|
|
77
|
+
totalPages: z
|
|
78
|
+
.number()
|
|
79
|
+
.int()
|
|
80
|
+
.min(1)
|
|
81
|
+
.describe(param('ingest_create_document', 'totalPages')),
|
|
82
|
+
scope: z
|
|
83
|
+
.string()
|
|
84
|
+
.max(300)
|
|
85
|
+
.optional()
|
|
86
|
+
.describe(param('ingest_create_document', 'scope')),
|
|
87
|
+
edition: z
|
|
88
|
+
.string()
|
|
89
|
+
.max(20)
|
|
90
|
+
.optional()
|
|
91
|
+
.describe(param('ingest_create_document', 'edition')),
|
|
74
92
|
},
|
|
75
|
-
annotations: write,
|
|
76
93
|
run: async (client, args) => ({
|
|
77
94
|
documentId: await client.action(api.ingestionApi.createDocument, {
|
|
78
95
|
apiKey: requireApiKey(),
|
|
@@ -81,14 +98,15 @@ export const ingestCreateDocument = defineTool({
|
|
|
81
98
|
}),
|
|
82
99
|
});
|
|
83
100
|
export const ingestCreateSections = defineTool({
|
|
84
|
-
|
|
85
|
-
title: 'Create sections',
|
|
86
|
-
description: 'Bulk-insert sections into a draft document. Parent links resolve via parentNodeId within the batch + already-inserted sections. Returns a map of nodeId → sectionId (use those ids to attach formulas/tables/figures/cross-refs).',
|
|
101
|
+
...headOf('ingest_create_sections'),
|
|
87
102
|
inputSchema: {
|
|
88
|
-
documentId,
|
|
89
|
-
sections: z
|
|
103
|
+
documentId: documentId('ingest_create_sections'),
|
|
104
|
+
sections: z
|
|
105
|
+
.array(sectionInput)
|
|
106
|
+
.min(1)
|
|
107
|
+
.max(200)
|
|
108
|
+
.describe(param('ingest_create_sections', 'sections')),
|
|
90
109
|
},
|
|
91
|
-
annotations: write,
|
|
92
110
|
run: async (client, args) => ({
|
|
93
111
|
sections: await client.action(api.ingestionApi.createSections, {
|
|
94
112
|
apiKey: requireApiKey(),
|
|
@@ -98,16 +116,17 @@ export const ingestCreateSections = defineTool({
|
|
|
98
116
|
}),
|
|
99
117
|
});
|
|
100
118
|
export const ingestAttachFormula = defineTool({
|
|
101
|
-
|
|
102
|
-
title: 'Attach formula',
|
|
103
|
-
description: 'Attach a LaTeX formula to a section.',
|
|
119
|
+
...headOf('ingest_attach_formula'),
|
|
104
120
|
inputSchema: {
|
|
105
|
-
sectionId,
|
|
106
|
-
latex: z.string().min(1),
|
|
107
|
-
description: z
|
|
108
|
-
|
|
121
|
+
sectionId: sectionId('ingest_attach_formula'),
|
|
122
|
+
latex: z.string().min(1).describe(param('ingest_attach_formula', 'latex')),
|
|
123
|
+
description: z
|
|
124
|
+
.string()
|
|
125
|
+
.describe(param('ingest_attach_formula', 'description')),
|
|
126
|
+
formulaNumber: z
|
|
127
|
+
.string()
|
|
128
|
+
.describe(param('ingest_attach_formula', 'formulaNumber')),
|
|
109
129
|
},
|
|
110
|
-
annotations: write,
|
|
111
130
|
run: async (client, args) => ({
|
|
112
131
|
formulaId: await client.action(api.ingestionApi.attachFormula, {
|
|
113
132
|
apiKey: requireApiKey(),
|
|
@@ -116,25 +135,24 @@ export const ingestAttachFormula = defineTool({
|
|
|
116
135
|
}),
|
|
117
136
|
});
|
|
118
137
|
export const ingestAttachTable = defineTool({
|
|
119
|
-
|
|
120
|
-
title: 'Attach table',
|
|
121
|
-
description: 'Attach a structured table to a section. `data` is { headers: string[], rows: string[][] }.',
|
|
138
|
+
...headOf('ingest_attach_table'),
|
|
122
139
|
inputSchema: {
|
|
123
|
-
sectionId,
|
|
140
|
+
sectionId: sectionId('ingest_attach_table'),
|
|
124
141
|
// Cells are coerced rather than required to be strings. Every table
|
|
125
142
|
// currently stored has string cells, but a norm table is full of figures
|
|
126
|
-
// and an agent will sooner or later send `2400` instead of `"2400"
|
|
143
|
+
// and an agent will sooner or later send `2400` instead of `"2400"`;
|
|
127
144
|
// failing mid-ingestion over that would cost far more than normalising it.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
data: z.object({
|
|
145
|
+
data: z
|
|
146
|
+
.object({
|
|
131
147
|
headers: z.array(z.coerce.string()),
|
|
132
148
|
rows: z.array(z.array(z.coerce.string())),
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
|
|
149
|
+
})
|
|
150
|
+
.describe(param('ingest_attach_table', 'data')),
|
|
151
|
+
caption: z.string().describe(param('ingest_attach_table', 'caption')),
|
|
152
|
+
tableNumber: z
|
|
153
|
+
.string()
|
|
154
|
+
.describe(param('ingest_attach_table', 'tableNumber')),
|
|
136
155
|
},
|
|
137
|
-
annotations: write,
|
|
138
156
|
run: async (client, args) => ({
|
|
139
157
|
tableId: await client.action(api.ingestionApi.attachTable, {
|
|
140
158
|
apiKey: requireApiKey(),
|
|
@@ -143,17 +161,25 @@ export const ingestAttachTable = defineTool({
|
|
|
143
161
|
}),
|
|
144
162
|
});
|
|
145
163
|
export const ingestAttachCrossRef = defineTool({
|
|
146
|
-
|
|
147
|
-
title: 'Attach cross-reference',
|
|
148
|
-
description: 'Attach a cross-reference from a section to another norm/section.',
|
|
164
|
+
...headOf('ingest_attach_cross_ref'),
|
|
149
165
|
inputSchema: {
|
|
150
|
-
sourceSectionId:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
sourceSectionId: z
|
|
167
|
+
.string()
|
|
168
|
+
.min(1)
|
|
169
|
+
.describe(param('ingest_attach_cross_ref', 'sourceSectionId')),
|
|
170
|
+
targetDocumentCode: z
|
|
171
|
+
.string()
|
|
172
|
+
.min(1)
|
|
173
|
+
.describe(param('ingest_attach_cross_ref', 'targetDocumentCode')),
|
|
174
|
+
targetSectionPath: z
|
|
175
|
+
.string()
|
|
176
|
+
.optional()
|
|
177
|
+
.describe(param('ingest_attach_cross_ref', 'targetSectionPath')),
|
|
178
|
+
refText: z.string().describe(param('ingest_attach_cross_ref', 'refText')),
|
|
179
|
+
refType: z
|
|
180
|
+
.enum(['explicit', 'implicit'])
|
|
181
|
+
.describe(param('ingest_attach_cross_ref', 'refType')),
|
|
155
182
|
},
|
|
156
|
-
annotations: write,
|
|
157
183
|
run: async (client, args) => ({
|
|
158
184
|
crossRefId: await client.action(api.ingestionApi.attachCrossRef, {
|
|
159
185
|
apiKey: requireApiKey(),
|
|
@@ -162,20 +188,18 @@ export const ingestAttachCrossRef = defineTool({
|
|
|
162
188
|
}),
|
|
163
189
|
});
|
|
164
190
|
export const ingestUploadFigure = defineTool({
|
|
165
|
-
|
|
166
|
-
title: 'Upload figure',
|
|
167
|
-
description: 'Upload a figure image (base64) and attach it to a section. mimeType must be image/png, image/jpeg or image/webp; max 8 MB.',
|
|
191
|
+
...headOf('ingest_upload_figure'),
|
|
168
192
|
inputSchema: {
|
|
169
|
-
sectionId,
|
|
170
|
-
base64: z
|
|
193
|
+
sectionId: sectionId('ingest_upload_figure'),
|
|
194
|
+
base64: z.string().min(1).describe(param('ingest_upload_figure', 'base64')),
|
|
195
|
+
mimeType: z
|
|
196
|
+
.enum(['image/png', 'image/jpeg', 'image/webp'])
|
|
197
|
+
.describe(param('ingest_upload_figure', 'mimeType')),
|
|
198
|
+
caption: z.string().describe(param('ingest_upload_figure', 'caption')),
|
|
199
|
+
figureNumber: z
|
|
171
200
|
.string()
|
|
172
|
-
.
|
|
173
|
-
.describe('Base64-encoded image bytes (data: prefix tolerated).'),
|
|
174
|
-
mimeType: z.enum(['image/png', 'image/jpeg', 'image/webp']),
|
|
175
|
-
caption: z.string(),
|
|
176
|
-
figureNumber: z.string(),
|
|
201
|
+
.describe(param('ingest_upload_figure', 'figureNumber')),
|
|
177
202
|
},
|
|
178
|
-
annotations: write,
|
|
179
203
|
run: async (client, args) => ({
|
|
180
204
|
figureId: await client.action(api.ingestionApi.uploadFigure, {
|
|
181
205
|
apiKey: requireApiKey(),
|
|
@@ -184,37 +208,31 @@ export const ingestUploadFigure = defineTool({
|
|
|
184
208
|
}),
|
|
185
209
|
});
|
|
186
210
|
export const ingestNormalizeCrossRefs = defineTool({
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
description: 'Scan all sections of a document and (re)build cross-references to other norms detected in the text. Idempotent.',
|
|
190
|
-
inputSchema: { documentId },
|
|
191
|
-
annotations: { ...write, idempotentHint: true },
|
|
211
|
+
...headOf('ingest_normalize_cross_refs'),
|
|
212
|
+
inputSchema: { documentId: documentId('ingest_normalize_cross_refs') },
|
|
192
213
|
run: (client, args) => client.action(api.ingestionApi.normalizeCrossRefs, {
|
|
193
214
|
apiKey: requireApiKey(),
|
|
194
215
|
documentId: args.documentId,
|
|
195
216
|
}),
|
|
196
217
|
});
|
|
197
218
|
export const ingestPublish = defineTool({
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
219
|
+
...headOf('ingest_publish'),
|
|
220
|
+
inputSchema: {
|
|
221
|
+
documentId: documentId('ingest_publish'),
|
|
222
|
+
force: z.boolean().optional().describe(param('ingest_publish', 'force')),
|
|
223
|
+
},
|
|
203
224
|
run: async (client, args) => {
|
|
204
|
-
await client.action(api.ingestionApi.publishDocument, {
|
|
225
|
+
const quality = await client.action(api.ingestionApi.publishDocument, {
|
|
205
226
|
apiKey: requireApiKey(),
|
|
206
227
|
documentId: args.documentId,
|
|
228
|
+
force: args.force,
|
|
207
229
|
});
|
|
208
|
-
return { published: true };
|
|
230
|
+
return { published: true, quality };
|
|
209
231
|
},
|
|
210
232
|
});
|
|
211
233
|
export const ingestDelete = defineTool({
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
description: 'Delete a document and all its sections/figures/tables/formulas/cross-refs. Use before re-ingesting.',
|
|
215
|
-
inputSchema: { documentId },
|
|
216
|
-
// The one genuinely destructive tool. Clients use this hint to confirm.
|
|
217
|
-
annotations: { ...write, destructiveHint: true },
|
|
234
|
+
...headOf('ingest_delete'),
|
|
235
|
+
inputSchema: { documentId: documentId('ingest_delete') },
|
|
218
236
|
run: async (client, args) => {
|
|
219
237
|
await client.action(api.ingestionApi.deleteDocument, {
|
|
220
238
|
apiKey: requireApiKey(),
|
package/dist/tools/read.d.ts
CHANGED
|
@@ -1,51 +1,76 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
export declare const getMethodology: import("./define.js").ToolDef<{
|
|
3
|
-
|
|
4
|
-
}>;
|
|
2
|
+
export declare const getMethodology: import("./define.js").ToolDef<{}>;
|
|
3
|
+
export declare const whoami: import("./define.js").ToolDef<{}>;
|
|
5
4
|
export declare const listNorms: import("./define.js").ToolDef<{}>;
|
|
6
5
|
export declare const getToc: import("./define.js").ToolDef<{
|
|
7
|
-
|
|
6
|
+
code: z.ZodString;
|
|
7
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
8
8
|
maxDepth: z.ZodOptional<z.ZodNumber>;
|
|
9
9
|
}>;
|
|
10
10
|
export declare const getSubtree: import("./define.js").ToolDef<{
|
|
11
|
-
|
|
11
|
+
code: z.ZodString;
|
|
12
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
12
13
|
path: z.ZodString;
|
|
13
14
|
maxDepth: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
maxNodes: z.ZodOptional<z.ZodNumber>;
|
|
14
16
|
}>;
|
|
15
17
|
export declare const getSection: import("./define.js").ToolDef<{
|
|
16
|
-
|
|
18
|
+
code: z.ZodString;
|
|
19
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
17
20
|
path: z.ZodString;
|
|
21
|
+
maxChars: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
18
23
|
}>;
|
|
19
24
|
export declare const searchInNorm: import("./define.js").ToolDef<{
|
|
20
|
-
|
|
25
|
+
code: z.ZodString;
|
|
26
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
27
|
+
keyword: z.ZodString;
|
|
28
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const searchCorpus: import("./define.js").ToolDef<{
|
|
21
31
|
keyword: z.ZodString;
|
|
22
32
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
23
33
|
}>;
|
|
24
34
|
export declare const getCrossRefs: import("./define.js").ToolDef<{
|
|
25
|
-
|
|
35
|
+
code: z.ZodString;
|
|
36
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
26
37
|
path: z.ZodString;
|
|
27
38
|
}>;
|
|
28
39
|
export declare const getFigure: import("./define.js").ToolDef<{
|
|
29
|
-
|
|
40
|
+
code: z.ZodString;
|
|
41
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
30
42
|
figureId: z.ZodString;
|
|
31
43
|
}>;
|
|
32
|
-
export declare const readTools: (import("./define.js").ToolDef<{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
norm: z.ZodString;
|
|
44
|
+
export declare const readTools: (import("./define.js").ToolDef<{}> | import("./define.js").ToolDef<{
|
|
45
|
+
code: z.ZodString;
|
|
46
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
36
47
|
maxDepth: z.ZodOptional<z.ZodNumber>;
|
|
37
48
|
}> | import("./define.js").ToolDef<{
|
|
38
|
-
|
|
49
|
+
code: z.ZodString;
|
|
50
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
39
51
|
path: z.ZodString;
|
|
40
52
|
maxDepth: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
maxNodes: z.ZodOptional<z.ZodNumber>;
|
|
41
54
|
}> | import("./define.js").ToolDef<{
|
|
42
|
-
|
|
55
|
+
code: z.ZodString;
|
|
56
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
43
57
|
path: z.ZodString;
|
|
58
|
+
maxChars: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
44
60
|
}> | import("./define.js").ToolDef<{
|
|
45
|
-
|
|
61
|
+
code: z.ZodString;
|
|
62
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
46
63
|
keyword: z.ZodString;
|
|
47
64
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
48
65
|
}> | import("./define.js").ToolDef<{
|
|
49
|
-
|
|
66
|
+
keyword: z.ZodString;
|
|
67
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
}> | import("./define.js").ToolDef<{
|
|
69
|
+
code: z.ZodString;
|
|
70
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
71
|
+
path: z.ZodString;
|
|
72
|
+
}> | import("./define.js").ToolDef<{
|
|
73
|
+
code: z.ZodString;
|
|
74
|
+
edition: z.ZodOptional<z.ZodString>;
|
|
50
75
|
figureId: z.ZodString;
|
|
51
76
|
}>)[];
|