@stratta/mcp 0.10.0 → 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 +37 -3
- 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 +48 -0
- package/dist/tools/dossier.js +249 -127
- 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/README.md
CHANGED
|
@@ -152,18 +152,35 @@ settings come from environment variables — see [`.env.example`](./.env.example
|
|
|
152
152
|
| `STRATTA_API_KEY` | no¹ | – | API key from https://stratta.ch. ¹If unset, the server falls back to `~/.stratta/config.json`, or prompts you on first use (clients that support elicitation). |
|
|
153
153
|
| `STRATTA_CONVEX_URL` | no | Stratta prod backend | Override only if you self-host. |
|
|
154
154
|
|
|
155
|
+
## Tests
|
|
156
|
+
|
|
157
|
+
`npm test` runs the unit tests. The two integration suites
|
|
158
|
+
(`tests/handlers.test.ts`, `tests/dossier-flow.e2e.test.ts`) run this checkout's
|
|
159
|
+
built server against the deployment you name, and are skipped when either
|
|
160
|
+
variable is missing:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm run build
|
|
164
|
+
STRATTA_E2E_URL=https://<dev-deployment>.convex.cloud STRATTA_E2E_API_KEY=sk_strt_... npm test
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Point them at a development deployment: the dossier flow creates a dossier
|
|
168
|
+
named `E2E dossier <timestamp>` and does not delete it.
|
|
169
|
+
|
|
155
170
|
## Tools exposed
|
|
156
171
|
|
|
157
|
-
**Read** (
|
|
172
|
+
**Read** (9 tools — query norms in your workspace):
|
|
158
173
|
|
|
159
174
|
| Tool | Purpose |
|
|
160
175
|
| ----------------- | -------------------------------------------------------------------------------------- |
|
|
161
176
|
| `get_methodology` | Behavioural contract: persona, workflow, meta-routing hints, answer rules. Call first. |
|
|
162
|
-
| `
|
|
177
|
+
| `whoami` | Which organisation, role and plan this key reads as, and how many norms it sees. |
|
|
178
|
+
| `list_norms` | List all norms published in your workspace (code, year, title, language, coverage). |
|
|
163
179
|
| `get_toc` | Hierarchical TOC for a norm (default `maxDepth=1` = chapters). |
|
|
164
180
|
| `get_subtree` | Drill into a chapter/section subtree (`path` + `maxDepth`). |
|
|
165
181
|
| `get_section` | Full enriched content of a section (formulas, tables, figures, cross-refs). |
|
|
166
182
|
| `search_in_norm` | Keyword search inside a norm. |
|
|
183
|
+
| `search_corpus` | Keyword search across every norm of the workspace, grouped by norm. |
|
|
167
184
|
| `get_figure` | Retrieve a figure inline (base64 ImageContent) + public URL. |
|
|
168
185
|
| `get_cross_refs` | Outgoing cross-refs from a section to other norms. |
|
|
169
186
|
|
|
@@ -205,10 +222,27 @@ For querying:
|
|
|
205
222
|
2. Call `list_norms` to see what's available in your workspace.
|
|
206
223
|
3. Call `get_toc(norm)` to navigate the structure; `get_subtree` to drill in.
|
|
207
224
|
4. Call `get_section(norm, path)` to read specific content.
|
|
208
|
-
5. Use `search_in_norm` when the section path is
|
|
225
|
+
5. Use `search_corpus` when the norm is unknown, `search_in_norm` when the section path is.
|
|
209
226
|
6. Follow `crossRefs` for compound questions (e.g. SIA 261 → SIA 263 → EC).
|
|
210
227
|
7. Call `get_figure` when the section references a figure relevant to the answer.
|
|
211
228
|
|
|
229
|
+
Two skills ship in the package: **`consult-stratta`** (the working method an agent
|
|
230
|
+
follows to answer from the norms, generated from the same text the server serves
|
|
231
|
+
through `get_methodology`) and **`ingest-norm`**.
|
|
232
|
+
|
|
233
|
+
## Resources and prompts
|
|
234
|
+
|
|
235
|
+
Four `stratta://` resources can be pinned to a conversation or read without a
|
|
236
|
+
tool call, each scoped to your workspace: `stratta://norms` (JSON),
|
|
237
|
+
`stratta://methodology` (Markdown), `stratta://norm/{code}/toc` (the table of
|
|
238
|
+
contents to depth 2, code URL-encoded, e.g. `stratta://norm/SIA%20267/toc`) and
|
|
239
|
+
`stratta://dossier/{id}` (a project dossier as Markdown). The same four are
|
|
240
|
+
served by the remote connector.
|
|
241
|
+
|
|
242
|
+
Three prompts appear as slash commands in clients that support them:
|
|
243
|
+
`investigate-question` (question, project?), `resume-dossier` (name) and
|
|
244
|
+
`check-value` (value, norm?).
|
|
245
|
+
|
|
212
246
|
For ingesting your own licensed norms, see the bundled **`ingest-norm` skill** —
|
|
213
247
|
a 2-phase hybrid pipeline (since 0.4.0): a Python pre-pass
|
|
214
248
|
(`scripts/ingest-prepass.py`, PyMuPDF) extracts the hierarchical tree and
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The confirmation step before a decision is written, on stdio.
|
|
5
|
+
*
|
|
6
|
+
* Same contract as the remote gate: `confirmed: true` in the arguments means
|
|
7
|
+
* the agent already asked the user; otherwise the client is asked through an
|
|
8
|
+
* elicitation when it supports one, and told to come back with
|
|
9
|
+
* `confirmed: true` when it does not. The Convex function never sees the
|
|
10
|
+
* difference.
|
|
11
|
+
*/
|
|
12
|
+
export declare const CONFIRMED_TOOLS: Record<string, (args: Record<string, unknown>) => string>;
|
|
13
|
+
export declare const CONFIRMATION_HINT: string;
|
|
14
|
+
/** `null` when the call may proceed, a tool result to return otherwise. */
|
|
15
|
+
export declare function confirmWithUser(server: Pick<Server, 'getClientCapabilities' | 'elicitInput'>, toolName: string, args: Record<string, unknown>): Promise<CallToolResult | null>;
|
package/dist/confirm.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The confirmation step before a decision is written, on stdio.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the remote gate: `confirmed: true` in the arguments means
|
|
5
|
+
* the agent already asked the user; otherwise the client is asked through an
|
|
6
|
+
* elicitation when it supports one, and told to come back with
|
|
7
|
+
* `confirmed: true` when it does not. The Convex function never sees the
|
|
8
|
+
* difference.
|
|
9
|
+
*/
|
|
10
|
+
export const CONFIRMED_TOOLS = {
|
|
11
|
+
record_decision: (args) => [
|
|
12
|
+
args.title,
|
|
13
|
+
args.value ? `= ${String(args.value)}` : null,
|
|
14
|
+
args.retainedOption ? `(option ${String(args.retainedOption)})` : null,
|
|
15
|
+
]
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.map(String)
|
|
18
|
+
.join(' '),
|
|
19
|
+
resolve_question: (args) => args.resolved === false
|
|
20
|
+
? 'reopen this question'
|
|
21
|
+
: 'close this question without a decision',
|
|
22
|
+
};
|
|
23
|
+
export const CONFIRMATION_HINT = 'Not recorded: this client cannot ask the user directly. Confirm the ' +
|
|
24
|
+
'decision with the user in the conversation, then call again with ' +
|
|
25
|
+
'confirmed: true.';
|
|
26
|
+
/** `null` when the call may proceed, a tool result to return otherwise. */
|
|
27
|
+
export async function confirmWithUser(server, toolName, args) {
|
|
28
|
+
const summary = CONFIRMED_TOOLS[toolName];
|
|
29
|
+
if (!summary || args.confirmed === true)
|
|
30
|
+
return null;
|
|
31
|
+
if (!server.getClientCapabilities()?.elicitation) {
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: 'text', text: CONFIRMATION_HINT }],
|
|
34
|
+
structuredContent: { outcome: 'confirmation_required' },
|
|
35
|
+
isError: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const result = await server.elicitInput({
|
|
39
|
+
mode: 'form',
|
|
40
|
+
message: `${toolName === 'record_decision' ? 'Decision' : 'Question'}: ${summary(args)}\n\nRecord it in the dossier?`,
|
|
41
|
+
requestedSchema: {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: { confirm: { type: 'boolean', title: 'Record it' } },
|
|
44
|
+
required: ['confirm'],
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
if (result.action !== 'accept' || result.content?.confirm === false) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: 'text', text: 'Not recorded: the user declined.' }],
|
|
50
|
+
structuredContent: { outcome: 'declined' },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
package/dist/errors.js
CHANGED
|
@@ -4,6 +4,22 @@ function isQuotaPayload(data) {
|
|
|
4
4
|
data !== null &&
|
|
5
5
|
data.code === 'QUOTA_EXCEEDED');
|
|
6
6
|
}
|
|
7
|
+
function isQualityPayload(data) {
|
|
8
|
+
return (typeof data === 'object' &&
|
|
9
|
+
data !== null &&
|
|
10
|
+
data.code === 'QUALITY_TOO_LOW');
|
|
11
|
+
}
|
|
12
|
+
/** What each coverage flag means, in words the agent can relay. */
|
|
13
|
+
const FLAG_TEXT = {
|
|
14
|
+
'sparse-text': 'trop peu de texte par page : le contenu des sections est un résumé, pas le texte de la norme',
|
|
15
|
+
'light-text': 'peu de texte par page',
|
|
16
|
+
'few-sections': "moins de 5 sections : la détection des titres n'a rien trouvé",
|
|
17
|
+
'thin-sections': 'sections presque vides (moins de 200 caractères en moyenne)',
|
|
18
|
+
'low-coverage': 'les chapitres couvrent moins de la moitié des pages',
|
|
19
|
+
'empty-leaves': 'plus de 20 % des sections feuilles sont vides',
|
|
20
|
+
'duplicate-paths': 'plusieurs sections portent le même chemin',
|
|
21
|
+
'no-enrichment': 'aucune formule ni tableau attaché',
|
|
22
|
+
};
|
|
7
23
|
function humanDuration(ms) {
|
|
8
24
|
const days = Math.floor(ms / 86_400_000);
|
|
9
25
|
if (days >= 1)
|
|
@@ -22,6 +38,7 @@ const DOCS = 'https://stratta.ch/docs/fr';
|
|
|
22
38
|
*/
|
|
23
39
|
const HELP = {
|
|
24
40
|
QUOTA_EXCEEDED: `${DOCS}/account/plans#quand-une-limite-est-atteinte`,
|
|
41
|
+
QUALITY_TOO_LOW: `${DOCS}/guides/ingest-a-norm`,
|
|
25
42
|
UNAUTHORIZED: `${DOCS}/guides/get-api-key`,
|
|
26
43
|
NO_ORGANIZATION: `${DOCS}/guides/manage-organization`,
|
|
27
44
|
DOCUMENT_NOT_FOUND: `${DOCS}/guides/ingest-a-norm`,
|
|
@@ -59,6 +76,16 @@ export function formatToolError(err) {
|
|
|
59
76
|
lines.push('Ne relancez pas la même opération : elle échouera à l’identique tant que la limite est atteinte.');
|
|
60
77
|
return withHelp('QUOTA_EXCEEDED', lines);
|
|
61
78
|
}
|
|
79
|
+
if (isQualityPayload(data)) {
|
|
80
|
+
const lines = [
|
|
81
|
+
`Document non publié : score de couverture ${data.score}/100, sous le plancher de ${data.minimum}.`,
|
|
82
|
+
`Mesures : ${data.charsPerPage} caractères par page, ${Math.round(data.pagesCovered * 100)} % des pages sous un chapitre, ${data.sectionCount} sections.`,
|
|
83
|
+
...data.flags.map((f) => `- ${FLAG_TEXT[f] ?? f}`),
|
|
84
|
+
'Un agent qui lirait ce document répondrait depuis des résumés. Corrigez l’ingestion (le champ `content` de chaque section doit porter le texte de la norme, chaque chapitre ses pages) plutôt que de relancer la publication.',
|
|
85
|
+
'Si le document est réellement aussi court, demandez à l’utilisateur, puis rappelez `ingest_publish` avec `force: true`.',
|
|
86
|
+
];
|
|
87
|
+
return withHelp('QUALITY_TOO_LOW', lines);
|
|
88
|
+
}
|
|
62
89
|
if (typeof data === 'string') {
|
|
63
90
|
switch (data) {
|
|
64
91
|
case 'UNAUTHORIZED':
|
package/dist/index.js
CHANGED
|
@@ -8,9 +8,14 @@ import { createConvexClient, api } from './client.js';
|
|
|
8
8
|
import { formatToolError } from './errors.js';
|
|
9
9
|
import { ensureAuthenticated, resolveApiKey } from './auth.js';
|
|
10
10
|
import { elicitApiKey } from './elicit.js';
|
|
11
|
+
import { confirmWithUser } from './confirm.js';
|
|
11
12
|
import { readTools } from './tools/read.js';
|
|
12
13
|
import { ingestTools } from './tools/ingest.js';
|
|
13
14
|
import { dossierTools } from './tools/dossier.js';
|
|
15
|
+
import { SESSION_ID, usageDigest } from './usage.js';
|
|
16
|
+
import { SERVER_INSTRUCTIONS } from './tools/catalog.gen.js';
|
|
17
|
+
import { registerResources } from './resources.js';
|
|
18
|
+
import { registerPrompts } from './prompts.js';
|
|
14
19
|
/**
|
|
15
20
|
* Read from package.json rather than repeated in a literal. The previous
|
|
16
21
|
* version announced `0.3.0` while the published package was `0.6.0`, so every
|
|
@@ -32,7 +37,14 @@ function packageVersion() {
|
|
|
32
37
|
}
|
|
33
38
|
return '0.0.0';
|
|
34
39
|
}
|
|
35
|
-
const server = new McpServer({ name: 'stratta-mcp', version: packageVersion() },
|
|
40
|
+
const server = new McpServer({ name: 'stratta-mcp', version: packageVersion() },
|
|
41
|
+
// The same sentence the remote transport sends at initialisation. Not every
|
|
42
|
+
// client shows it to the model, which is why each tool description stands
|
|
43
|
+
// on its own; where it is shown, the two transports say the same thing.
|
|
44
|
+
{
|
|
45
|
+
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
46
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
47
|
+
});
|
|
36
48
|
const client = createConvexClient();
|
|
37
49
|
/**
|
|
38
50
|
* Everything every tool call needs, in one place: resolve the key (env, then
|
|
@@ -57,6 +69,8 @@ async function call(def, args) {
|
|
|
57
69
|
toolName: def.name,
|
|
58
70
|
status,
|
|
59
71
|
durationMs: Date.now() - startedAt,
|
|
72
|
+
sessionId: SESSION_ID,
|
|
73
|
+
argsDigest: usageDigest(args),
|
|
60
74
|
})
|
|
61
75
|
.catch((e) => console.error('[stratta-mcp] usage report failed:', e));
|
|
62
76
|
};
|
|
@@ -64,12 +78,19 @@ async function call(def, args) {
|
|
|
64
78
|
resolvedKey = resolveApiKey() ?? (await elicitApiKey(server.server, client));
|
|
65
79
|
await ensureAuthenticated(client, resolvedKey);
|
|
66
80
|
authenticated = true;
|
|
81
|
+
// A decision is written only once the user confirmed it: through the
|
|
82
|
+
// client when it can ask, through the agent otherwise (`confirm.ts`).
|
|
83
|
+
const gate = await confirmWithUser(server.server, def.name, (args ?? {}));
|
|
84
|
+
if (gate)
|
|
85
|
+
return gate;
|
|
67
86
|
const result = await def.run(client, args);
|
|
68
87
|
reportUsage();
|
|
69
88
|
if (def.toContent)
|
|
70
89
|
return def.toContent(result);
|
|
90
|
+
// Compact: the two-space indentation was a third more tokens on every
|
|
91
|
+
// section an agent read, for a reader that never looks at whitespace.
|
|
71
92
|
return {
|
|
72
|
-
content: [{ type: 'text', text: JSON.stringify(result
|
|
93
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
73
94
|
};
|
|
74
95
|
}
|
|
75
96
|
catch (err) {
|
|
@@ -92,6 +113,10 @@ for (const def of [...readTools, ...dossierTools, ...ingestTools]) {
|
|
|
92
113
|
// handler receives values that already match the declared shape.
|
|
93
114
|
(args) => call(def, args));
|
|
94
115
|
}
|
|
116
|
+
// Documents an agent can read without a tool call, and the three ways a
|
|
117
|
+
// user starts a conversation. Neither exists on the remote transport yet.
|
|
118
|
+
registerResources(server, client);
|
|
119
|
+
registerPrompts(server);
|
|
95
120
|
/**
|
|
96
121
|
* The help nobody had.
|
|
97
122
|
*
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type PromptEntry } from './tools/catalog.gen.js';
|
|
3
|
+
export declare function renderPrompt(p: PromptEntry, args: Record<string, unknown>): string;
|
|
4
|
+
export declare function registerPrompts(server: McpServer): void;
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { PROMPTS } from './tools/catalog.gen.js';
|
|
3
|
+
/**
|
|
4
|
+
* Prompts: the three ways a user starts a conversation with Stratta, as
|
|
5
|
+
* slash commands in the clients that support them (Claude Code, Claude
|
|
6
|
+
* Desktop, Cursor). stdio only: the remote gateway does not carry prompts yet.
|
|
7
|
+
*
|
|
8
|
+
* Text and arguments come from the catalogue, so a wording change is made
|
|
9
|
+
* once. `{{arg}}` is filled with the argument; an `optional` line is appended
|
|
10
|
+
* only when its argument was given.
|
|
11
|
+
*/
|
|
12
|
+
const fill = (template, args) => template.replace(/\{\{(\w+)\}\}/g, (_match, key) => String(args[key] ?? ''));
|
|
13
|
+
export function renderPrompt(p, args) {
|
|
14
|
+
let text = fill(p.text, args);
|
|
15
|
+
for (const [arg, line] of Object.entries(p.optional ?? {})) {
|
|
16
|
+
if (args[arg])
|
|
17
|
+
text += `\n${fill(line, args)}`;
|
|
18
|
+
}
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
21
|
+
export function registerPrompts(server) {
|
|
22
|
+
for (const p of PROMPTS) {
|
|
23
|
+
const shape = {};
|
|
24
|
+
for (const a of p.args) {
|
|
25
|
+
const s = z.string().describe(a.description);
|
|
26
|
+
shape[a.name] = a.required ? s : s.optional();
|
|
27
|
+
}
|
|
28
|
+
server.registerPrompt(p.name, { title: p.title, description: p.description, argsSchema: shape }, (args) => ({
|
|
29
|
+
messages: [
|
|
30
|
+
{
|
|
31
|
+
role: 'user',
|
|
32
|
+
content: {
|
|
33
|
+
type: 'text',
|
|
34
|
+
text: renderPrompt(p, args),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { api } from './client.js';
|
|
3
|
+
import { requireApiKey } from './auth.js';
|
|
4
|
+
async function read(client, uri) {
|
|
5
|
+
const content = (await client.action(api._mcp.readResource, {
|
|
6
|
+
apiKey: requireApiKey(),
|
|
7
|
+
uri,
|
|
8
|
+
}));
|
|
9
|
+
if (!content) {
|
|
10
|
+
throw new Error(`Nothing at ${uri}: the norm or dossier is not in this workspace. Read stratta://norms or call list_dossiers.`);
|
|
11
|
+
}
|
|
12
|
+
return { contents: [content] };
|
|
13
|
+
}
|
|
14
|
+
export function registerResources(server, client) {
|
|
15
|
+
server.registerResource('norms', 'stratta://norms', {
|
|
16
|
+
title: 'Readable norms',
|
|
17
|
+
description: 'The norms this workspace can read, with code, year, title, language, scope and coverage. JSON.',
|
|
18
|
+
mimeType: 'application/json',
|
|
19
|
+
}, (uri) => read(client, uri.href));
|
|
20
|
+
server.registerResource('methodology', 'stratta://methodology', {
|
|
21
|
+
title: 'Working method',
|
|
22
|
+
description: 'The working method served by get_methodology, as one Markdown document built for this workspace.',
|
|
23
|
+
mimeType: 'text/markdown',
|
|
24
|
+
}, (uri) => read(client, uri.href));
|
|
25
|
+
server.registerResource('norm-toc', new ResourceTemplate('stratta://norm/{code}/toc', { list: undefined }), {
|
|
26
|
+
title: 'Table of contents of a norm',
|
|
27
|
+
description: 'Chapters and X.Y sections of one norm with their summaries and pages, as Markdown. {code} is the norm code, URL-encoded (SIA%20267).',
|
|
28
|
+
mimeType: 'text/markdown',
|
|
29
|
+
}, (uri) => read(client, uri.href));
|
|
30
|
+
server.registerResource('dossier', new ResourceTemplate('stratta://dossier/{id}', { list: undefined }), {
|
|
31
|
+
title: 'Project dossier',
|
|
32
|
+
description: 'One project dossier as Markdown: its questions with evidence, options and decisions, then the evidence not yet filed. {id} is the dossierId from list_dossiers.',
|
|
33
|
+
mimeType: 'text/markdown',
|
|
34
|
+
}, (uri) => read(client, uri.href));
|
|
35
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type Transport = 'stdio' | 'remote';
|
|
2
|
+
export type ToolAnnotations = {
|
|
3
|
+
readOnlyHint: boolean;
|
|
4
|
+
destructiveHint: boolean;
|
|
5
|
+
idempotentHint: boolean;
|
|
6
|
+
openWorldHint: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type CatalogEntry = {
|
|
9
|
+
name: string;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
annotations: ToolAnnotations;
|
|
13
|
+
transports: Transport[];
|
|
14
|
+
params: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
export declare const SERVER_INSTRUCTIONS = "Stratta serves the construction norms of the signed-in organization, and only those. Call `get_methodology` before the first technical question of a conversation: it carries the navigation order, the citation rules and the dossier policy. Never answer a technical question from memory; a norm absent from `list_norms` cannot be read.";
|
|
17
|
+
export declare const CATALOG: CatalogEntry[];
|
|
18
|
+
export type PromptArg = {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
required: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type PromptEntry = {
|
|
24
|
+
name: string;
|
|
25
|
+
title: string;
|
|
26
|
+
description: string;
|
|
27
|
+
args: PromptArg[];
|
|
28
|
+
text: string;
|
|
29
|
+
optional?: Record<string, string>;
|
|
30
|
+
};
|
|
31
|
+
export declare const PROMPTS: PromptEntry[];
|
|
32
|
+
export declare function catalogEntry(name: string): CatalogEntry;
|
|
33
|
+
/** Description of one parameter, as the catalogue words it. */
|
|
34
|
+
export declare function param(tool: string, name: string): string;
|