@cotrrackpro-dev/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/assistant/compliance.d.ts +24 -0
- package/dist/assistant/compliance.js +60 -0
- package/dist/assistant/compliance.js.map +1 -0
- package/dist/assistant/crisis.d.ts +31 -0
- package/dist/assistant/crisis.js +62 -0
- package/dist/assistant/crisis.js.map +1 -0
- package/dist/assistant/index.d.ts +15 -0
- package/dist/assistant/index.js +16 -0
- package/dist/assistant/index.js.map +1 -0
- package/dist/assistant/levels.d.ts +43 -0
- package/dist/assistant/levels.js +102 -0
- package/dist/assistant/levels.js.map +1 -0
- package/dist/assistant/prompt.d.ts +20 -0
- package/dist/assistant/prompt.js +96 -0
- package/dist/assistant/prompt.js.map +1 -0
- package/dist/assistant/rbac.d.ts +45 -0
- package/dist/assistant/rbac.js +75 -0
- package/dist/assistant/rbac.js.map +1 -0
- package/dist/assistant/readability.d.ts +28 -0
- package/dist/assistant/readability.js +70 -0
- package/dist/assistant/readability.js.map +1 -0
- package/dist/auth/broker.d.ts +32 -0
- package/dist/auth/broker.js +48 -0
- package/dist/auth/broker.js.map +1 -0
- package/dist/auth/deviceFlow.d.ts +26 -0
- package/dist/auth/deviceFlow.js +65 -0
- package/dist/auth/deviceFlow.js.map +1 -0
- package/dist/auth/provider.d.ts +32 -0
- package/dist/auth/provider.js +29 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/community/badges.d.ts +19 -0
- package/dist/community/badges.js +19 -0
- package/dist/community/badges.js.map +1 -0
- package/dist/community/events.d.ts +30 -0
- package/dist/community/events.js +31 -0
- package/dist/community/events.js.map +1 -0
- package/dist/community/identity.d.ts +28 -0
- package/dist/community/identity.js +2 -0
- package/dist/community/identity.js.map +1 -0
- package/dist/community/index.d.ts +7 -0
- package/dist/community/index.js +8 -0
- package/dist/community/index.js.map +1 -0
- package/dist/community/org.d.ts +46 -0
- package/dist/community/org.js +32 -0
- package/dist/community/org.js.map +1 -0
- package/dist/community/tiers.d.ts +8 -0
- package/dist/community/tiers.js +40 -0
- package/dist/community/tiers.js.map +1 -0
- package/dist/community/types.d.ts +26 -0
- package/dist/community/types.js +2 -0
- package/dist/community/types.js.map +1 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.js +27 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +29 -0
- package/dist/core/errors.js +20 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/transport.d.ts +45 -0
- package/dist/core/transport.js +109 -0
- package/dist/core/transport.js.map +1 -0
- package/dist/diagram/core.d.ts +11 -0
- package/dist/diagram/core.js +12 -0
- package/dist/diagram/core.js.map +1 -0
- package/dist/diagram/extract.d.ts +17 -0
- package/dist/diagram/extract.js +213 -0
- package/dist/diagram/extract.js.map +1 -0
- package/dist/diagram/index.d.ts +2 -0
- package/dist/diagram/index.js +3 -0
- package/dist/diagram/index.js.map +1 -0
- package/dist/diagram/mermaid.d.ts +10 -0
- package/dist/diagram/mermaid.js +50 -0
- package/dist/diagram/mermaid.js.map +1 -0
- package/dist/diagram/prompt.d.ts +4 -0
- package/dist/diagram/prompt.js +16 -0
- package/dist/diagram/prompt.js.map +1 -0
- package/dist/diagram/types.d.ts +33 -0
- package/dist/diagram/types.js +2 -0
- package/dist/diagram/types.js.map +1 -0
- package/dist/diagram/validate.d.ts +13 -0
- package/dist/diagram/validate.js +48 -0
- package/dist/diagram/validate.js.map +1 -0
- package/dist/guide/compose.d.ts +10 -0
- package/dist/guide/compose.js +31 -0
- package/dist/guide/compose.js.map +1 -0
- package/dist/guide/core.d.ts +10 -0
- package/dist/guide/core.js +11 -0
- package/dist/guide/core.js.map +1 -0
- package/dist/guide/index.d.ts +2 -0
- package/dist/guide/index.js +3 -0
- package/dist/guide/index.js.map +1 -0
- package/dist/guide/prompt.d.ts +8 -0
- package/dist/guide/prompt.js +20 -0
- package/dist/guide/prompt.js.map +1 -0
- package/dist/guide/render.d.ts +9 -0
- package/dist/guide/render.js +180 -0
- package/dist/guide/render.js.map +1 -0
- package/dist/guide/types.d.ts +67 -0
- package/dist/guide/types.js +2 -0
- package/dist/guide/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/artifacts.generated.d.ts +19 -0
- package/dist/mcp/artifacts.generated.js +140 -0
- package/dist/mcp/artifacts.generated.js.map +1 -0
- package/dist/mcp/format.d.ts +10 -0
- package/dist/mcp/format.js +17 -0
- package/dist/mcp/format.js.map +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.js +18 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/knowledge.generated.d.ts +11 -0
- package/dist/mcp/knowledge.generated.js +12 -0
- package/dist/mcp/knowledge.generated.js.map +1 -0
- package/dist/mcp/prompt-modules.generated.d.ts +12 -0
- package/dist/mcp/prompt-modules.generated.js +19 -0
- package/dist/mcp/prompt-modules.generated.js.map +1 -0
- package/dist/mcp/roles.generated.d.ts +15 -0
- package/dist/mcp/roles.generated.js +25 -0
- package/dist/mcp/roles.generated.js.map +1 -0
- package/dist/mcp/safety.d.ts +35 -0
- package/dist/mcp/safety.js +76 -0
- package/dist/mcp/safety.js.map +1 -0
- package/dist/mcp/scenarios.generated.d.ts +13 -0
- package/dist/mcp/scenarios.generated.js +16 -0
- package/dist/mcp/scenarios.generated.js.map +1 -0
- package/dist/mcp/search.d.ts +13 -0
- package/dist/mcp/search.js +33 -0
- package/dist/mcp/search.js.map +1 -0
- package/dist/mcp/skills.generated.d.ts +17 -0
- package/dist/mcp/skills.generated.js +40 -0
- package/dist/mcp/skills.generated.js.map +1 -0
- package/dist/mcp/toolset.d.ts +31 -0
- package/dist/mcp/toolset.js +54 -0
- package/dist/mcp/toolset.js.map +1 -0
- package/dist/mcp/types.d.ts +96 -0
- package/dist/mcp/types.js +9 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/mcp/workflows.generated.d.ts +17 -0
- package/dist/mcp/workflows.generated.js +12 -0
- package/dist/mcp/workflows.generated.js.map +1 -0
- package/dist/nocode/core.d.ts +12 -0
- package/dist/nocode/core.js +13 -0
- package/dist/nocode/core.js.map +1 -0
- package/dist/nocode/examples.d.ts +28 -0
- package/dist/nocode/examples.js +218 -0
- package/dist/nocode/examples.js.map +1 -0
- package/dist/nocode/index.d.ts +2 -0
- package/dist/nocode/index.js +3 -0
- package/dist/nocode/index.js.map +1 -0
- package/dist/nocode/mermaid.d.ts +9 -0
- package/dist/nocode/mermaid.js +33 -0
- package/dist/nocode/mermaid.js.map +1 -0
- package/dist/nocode/prompt.d.ts +8 -0
- package/dist/nocode/prompt.js +46 -0
- package/dist/nocode/prompt.js.map +1 -0
- package/dist/nocode/runtime.d.ts +28 -0
- package/dist/nocode/runtime.js +113 -0
- package/dist/nocode/runtime.js.map +1 -0
- package/dist/nocode/simpleOps.d.ts +16 -0
- package/dist/nocode/simpleOps.js +137 -0
- package/dist/nocode/simpleOps.js.map +1 -0
- package/dist/nocode/types.d.ts +72 -0
- package/dist/nocode/types.js +12 -0
- package/dist/nocode/types.js.map +1 -0
- package/dist/nocode/validate.d.ts +17 -0
- package/dist/nocode/validate.js +136 -0
- package/dist/nocode/validate.js.map +1 -0
- package/dist/params/codegen.d.ts +8 -0
- package/dist/params/codegen.js +12 -0
- package/dist/params/codegen.js.map +1 -0
- package/dist/params/convert.d.ts +7 -0
- package/dist/params/convert.js +123 -0
- package/dist/params/convert.js.map +1 -0
- package/dist/params/core.d.ts +11 -0
- package/dist/params/core.js +12 -0
- package/dist/params/core.js.map +1 -0
- package/dist/params/fieldTypes.d.ts +26 -0
- package/dist/params/fieldTypes.js +29 -0
- package/dist/params/fieldTypes.js.map +1 -0
- package/dist/params/index.d.ts +3 -0
- package/dist/params/index.js +4 -0
- package/dist/params/index.js.map +1 -0
- package/dist/params/prompt.d.ts +4 -0
- package/dist/params/prompt.js +16 -0
- package/dist/params/prompt.js.map +1 -0
- package/dist/params/render.d.ts +5 -0
- package/dist/params/render.js +25 -0
- package/dist/params/render.js.map +1 -0
- package/dist/params/types.d.ts +76 -0
- package/dist/params/types.js +16 -0
- package/dist/params/types.js.map +1 -0
- package/dist/params/validate.d.ts +5 -0
- package/dist/params/validate.js +104 -0
- package/dist/params/validate.js.map +1 -0
- package/dist/resources/client.d.ts +58 -0
- package/dist/resources/client.js +79 -0
- package/dist/resources/client.js.map +1 -0
- package/dist/resources/types.d.ts +72 -0
- package/dist/resources/types.js +9 -0
- package/dist/resources/types.js.map +1 -0
- package/dist/workflow/assets.d.ts +8 -0
- package/dist/workflow/assets.js +16 -0
- package/dist/workflow/assets.js.map +1 -0
- package/dist/workflow/commands.d.ts +10 -0
- package/dist/workflow/commands.js +21 -0
- package/dist/workflow/commands.js.map +1 -0
- package/dist/workflow/core.d.ts +15 -0
- package/dist/workflow/core.js +16 -0
- package/dist/workflow/core.js.map +1 -0
- package/dist/workflow/index.d.ts +2 -0
- package/dist/workflow/index.js +3 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/stack.d.ts +11 -0
- package/dist/workflow/stack.js +40 -0
- package/dist/workflow/stack.js.map +1 -0
- package/dist/workflow/templates.d.ts +17 -0
- package/dist/workflow/templates.js +223 -0
- package/dist/workflow/templates.js.map +1 -0
- package/dist/workflow/types.d.ts +27 -0
- package/dist/workflow/types.js +2 -0
- package/dist/workflow/types.js.map +1 -0
- package/package.json +77 -0
- package/schemas/artifacts.index.json +1211 -0
- package/schemas/knowledge.index.json +49 -0
- package/schemas/prompt-modules.index.json +105 -0
- package/schemas/roles.index.json +431 -0
- package/schemas/scenarios.index.json +15 -0
- package/schemas/skills.index.json +670 -0
- package/schemas/workflows.index.json +462 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@cotrackpro/sdk` are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-07-05
|
|
6
|
+
|
|
7
|
+
Initial public release. Synced the catalog from the canonical
|
|
8
|
+
`cotrackpro-antigravity` model and added two first-class entities plus the
|
|
9
|
+
child-centered / trauma-informed taxonomy.
|
|
10
|
+
|
|
11
|
+
### Reliability
|
|
12
|
+
- **core/transport** — a per-request timeout (`timeoutMs`, default 30s, `0`
|
|
13
|
+
disables) via `AbortController`, so a hung connection can't hang a consumer;
|
|
14
|
+
surfaces as a retryable `network` error.
|
|
15
|
+
- **auth/deviceFlow** — the login poll loop tolerates a transient error
|
|
16
|
+
(network/timeout/`5xx`) and keeps polling to the deadline, while a terminal
|
|
17
|
+
`4xx` still fails fast.
|
|
18
|
+
- **nocode/validate** — `validateApp`/`appWarnings` guard a malformed app
|
|
19
|
+
(missing `nodes`/`variables`/`edges`/`settings`) instead of throwing a raw
|
|
20
|
+
`TypeError`.
|
|
21
|
+
- **params/convert** — `schemaToFields` rejects a non-object property value with a
|
|
22
|
+
clear error instead of a raw `TypeError`.
|
|
23
|
+
|
|
24
|
+
### Catalog + entities
|
|
25
|
+
- **mcp** — new generated registries: `SKILLS`/`SKILL_NAMES` (33) and
|
|
26
|
+
`KNOWLEDGE`/`KNOWLEDGE_NAMES` (5). Enriched existing registries: `WORKFLOWS`
|
|
27
|
+
carry `version`/`trigger`/`condition`/`safetyLevel`/`steps` (the real step
|
|
28
|
+
graph), `ROLES` carry `composes`/`promptModules`/`safetyLevel`/`chainsWith`,
|
|
29
|
+
`ARTIFACTS` carry `safetyFields`/`hasProvenance`/`safetyRelevant`, prompt
|
|
30
|
+
modules carry `knowledgeRefs`.
|
|
31
|
+
- **mcp/safety** — `safetyTagsFor`, `isChildCentered`, `isTraumaInformed`,
|
|
32
|
+
`roleIdsWithTag`, `skillNamesWithTag`, `knowledgeForModules`,
|
|
33
|
+
`guardrailModulesForWorkflow`; `GuardrailTag`/`SafetyLevel` types.
|
|
34
|
+
- **mcp/format** — `describeWorkflowStep`, `workflowWalkthrough`.
|
|
35
|
+
- **mcp** — `CotrackproToolset` gains `listSkills`, `listKnowledge`, `getWorkflow`.
|
|
36
|
+
- **guide** — `GuideWorkflowRef` gains `safetyLevel`/`walkthrough`; new
|
|
37
|
+
`GuideKnowledgeRef` + `GuideInput.knowledge`; the renderer emits a workflow
|
|
38
|
+
step graph and a background-knowledge section.
|
|
39
|
+
- **nocode** — new guardrail-aware starter app `coparent-message-rewrite`
|
|
40
|
+
(calls the `cotrackpro` MCP `rewrite_coparent_message` tool).
|
|
41
|
+
|
|
42
|
+
### Foundations
|
|
43
|
+
- **core** — `Transport` (fetch + retry/backoff + timeout, `x-request-id` capture,
|
|
44
|
+
uniform error model), `resolveSdkConfig`, framework-agnostic `CotrackproError`.
|
|
45
|
+
- **auth** — pluggable `AuthProvider`: `StaticTokenProvider`, `CallbackTokenProvider`,
|
|
46
|
+
`DeviceFlowProvider`, `AnonymousProvider`.
|
|
47
|
+
- **resources** — `createClient()` with typed `whoami`, `orgs`, `packages`, `auth`, `health`.
|
|
48
|
+
- **mcp** — `CotrackproToolset` plus generated, offline, typed registries:
|
|
49
|
+
artifacts (133), roles (18), workflows (5), scenarios (9), prompt modules (12);
|
|
50
|
+
`searchArtifactsLocal` fuzzy search.
|
|
51
|
+
- Ships built `dist` (ESM + `.d.ts`); runtime-agnostic (Node, edge, browser, agent hosts).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Doug Devitre / CoTrackPro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# @cotrackpro/sdk
|
|
2
|
+
|
|
3
|
+
The typed TypeScript client for the CoTrackPro platform. One place for transport,
|
|
4
|
+
auth, typed API resources, and MCP/artifact bindings — consumed by the CLI and
|
|
5
|
+
every `cotrackpro*` repo, and built to be lifted into `cotrackpro-foundations`
|
|
6
|
+
and published.
|
|
7
|
+
|
|
8
|
+
## Why this exists
|
|
9
|
+
|
|
10
|
+
Before the SDK, each repo (and the CLI) hand-rolled `fetch`, bearer auth,
|
|
11
|
+
org-scoping, retries, and an ad-hoc error model. The SDK collapses that into a
|
|
12
|
+
single, well-tested surface that runs anywhere `fetch` exists — Node, edge,
|
|
13
|
+
browser, and agent/IDE hosts such as Google Antigravity.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createClient, StaticTokenProvider } from "@cotrackpro/sdk";
|
|
19
|
+
|
|
20
|
+
const cp = createClient({
|
|
21
|
+
baseUrl: "https://api.cotrackpro.com",
|
|
22
|
+
org: "acme",
|
|
23
|
+
auth: new StaticTokenProvider(process.env.COTRACKPRO_TOKEN!),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const me = await cp.whoami();
|
|
27
|
+
const orgs = await cp.orgs.list();
|
|
28
|
+
const pkgs = await cp.packages.list();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Auth providers
|
|
32
|
+
|
|
33
|
+
Pick the provider that matches your runtime — the rest of the SDK is identical:
|
|
34
|
+
|
|
35
|
+
| Provider | Use case |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `StaticTokenProvider` | API keys / env tokens — CI, agents, Antigravity |
|
|
38
|
+
| `CallbackTokenProvider` | Read a token lazily from a keychain / store (the CLI) |
|
|
39
|
+
| `DeviceFlowProvider` | Browser device-flow sign-in (CLI, desktop, IDE) |
|
|
40
|
+
| `AnonymousProvider` | Unauthenticated endpoints (health, device start) |
|
|
41
|
+
|
|
42
|
+
## MCP / artifacts
|
|
43
|
+
|
|
44
|
+
`@cotrackpro/sdk/mcp` exposes typed bindings over the CoTrackPro MCP server plus
|
|
45
|
+
a generated registry of all platform artifacts:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import {
|
|
49
|
+
ARTIFACTS, ARTIFACT_NAMES, type ArtifactName,
|
|
50
|
+
ROLES, WORKFLOWS, SCENARIOS, PROMPT_MODULES,
|
|
51
|
+
searchArtifactsLocal, CotrackproToolset,
|
|
52
|
+
} from "@cotrackpro/sdk/mcp";
|
|
53
|
+
|
|
54
|
+
ARTIFACTS["parenting-plan-draft"].dataSensitivity; // "confidential"
|
|
55
|
+
ROLES["cotrackpro-judge"].airtableRoleNames; // ["Judge", ...]
|
|
56
|
+
searchArtifactsLocal("incident"); // offline fuzzy search, ranked
|
|
57
|
+
|
|
58
|
+
// In an MCP-capable host (Claude runtime, Antigravity), pass a tool-call fn:
|
|
59
|
+
const cp = new CotrackproToolset((name, args) => host.callTool(`cotrackpro.${name}`, args));
|
|
60
|
+
const artifacts = await cp.listArtifacts();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Offline, typed, generated registries (no network/auth): `ARTIFACTS` (133),
|
|
64
|
+
`ROLES` (18), `WORKFLOWS` (5), `SCENARIOS` (9), `PROMPT_MODULES` (12) — each with an
|
|
65
|
+
id union, a `Record<Id, Meta>`, and an ids array. `searchArtifactsLocal` ranks
|
|
66
|
+
matches over the artifact registry.
|
|
67
|
+
|
|
68
|
+
### Regenerating artifact types
|
|
69
|
+
|
|
70
|
+
The registries are generated from snapshots of the MCP catalog
|
|
71
|
+
(`schemas/*.index.json`, synced via the MCP `list_*` tools):
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm run codegen # artifacts + roles/workflows/scenarios/prompt-modules -> src/mcp/*.generated.ts
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
To also generate field-level interfaces, drop per-artifact JSON Schemas (from the
|
|
78
|
+
MCP `get_artifact_schema` tool) into `schemas/full/<name>.json` and re-run codegen.
|
|
79
|
+
|
|
80
|
+
## Custom parameter sets (`@cotrackpro/sdk/params`)
|
|
81
|
+
|
|
82
|
+
User-authored **parameter sets** — custom typed field schemas — share one source of truth
|
|
83
|
+
across the CLI (`cotrackpro params`) and the portal builder:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { fieldsToSchema, validateValues, renderMarkdown, type ParamSet } from "@cotrackpro/sdk/params";
|
|
87
|
+
|
|
88
|
+
const set: ParamSet = { title: "Incident", dataSensitivity: "confidential", fields: [/* ... */] };
|
|
89
|
+
const schema = fieldsToSchema(set); // canonical JSON Schema (Draft 2020-12)
|
|
90
|
+
const { valid, errors } = validateValues(set, vals); // value validation (no ajv)
|
|
91
|
+
const doc = renderMarkdown(set, vals); // filled markdown document
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The module's **core is import-free** (no `node:`/external deps) so its compiled output loads
|
|
95
|
+
directly in the browser — the portal builder imports the very same `convert`/`validate`/`render`
|
|
96
|
+
logic. `FIELD_TYPES`/`FIELD_TYPE_LIST` is the single declarative registry that drives the
|
|
97
|
+
converter, both validators, the renderer, and the builder's widgets. `schemaToInterface`
|
|
98
|
+
(Node-only, in `params/codegen.ts`) compiles a set to a TypeScript interface and is shared with
|
|
99
|
+
`scripts/gen-artifacts.ts`.
|
|
100
|
+
|
|
101
|
+
> The parameter-set format is intentionally **the same shared shape** the CoTrackPro
|
|
102
|
+
> Intervention Builder uses to author items/templates — one format, two entry points (offline
|
|
103
|
+
> CLI/portal convenience vs. the Builder's governed authoring path). See
|
|
104
|
+
> [`../docs/strategy/three-surfaces.md`](../docs/strategy/three-surfaces.md) for the rationale
|
|
105
|
+
> and the producer→contract→consumer model.
|
|
106
|
+
|
|
107
|
+
## Testing
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm test # from the repo root — runs the SDK unit tests via vitest
|
|
111
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance guard — Build Buddy is a build *copilot*, never an advice service. This is
|
|
3
|
+
* the coded line (not just a disclaimer) that keeps it from giving legal, medical, or
|
|
4
|
+
* mental-health advice. Dependency-free and shared by every surface (web + Slack).
|
|
5
|
+
*
|
|
6
|
+
* Posture (decided): block advice *applied to the user's own situation*, but still answer
|
|
7
|
+
* general/building questions. A disclaimer alone is not a defense (UPL law), so the broker
|
|
8
|
+
* short-circuits on a match BEFORE calling the model — same shape as crisis detection.
|
|
9
|
+
*
|
|
10
|
+
* NOTE: the refusal copy + the patterns below are pending review by a licensed attorney
|
|
11
|
+
* and a clinician before live answers are enabled (see the proposal's launch gate).
|
|
12
|
+
*/
|
|
13
|
+
export type AdviceDomain = "legal" | "medical" | "mental-health";
|
|
14
|
+
export interface AdviceMatch {
|
|
15
|
+
matched: boolean;
|
|
16
|
+
domain?: AdviceDomain;
|
|
17
|
+
}
|
|
18
|
+
/** Detect a request for advice applied to the user's situation. Conservative by design. */
|
|
19
|
+
export declare function detectAdviceRequest(text: string): AdviceMatch;
|
|
20
|
+
/**
|
|
21
|
+
* The scoped, non-advice response. Acknowledges, declines the advice, routes to a
|
|
22
|
+
* licensed professional, and keeps the door open for build help. (Copy pending SME review.)
|
|
23
|
+
*/
|
|
24
|
+
export declare function adviceRefusal(domain: AdviceDomain, joinUrl?: string): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance guard — Build Buddy is a build *copilot*, never an advice service. This is
|
|
3
|
+
* the coded line (not just a disclaimer) that keeps it from giving legal, medical, or
|
|
4
|
+
* mental-health advice. Dependency-free and shared by every surface (web + Slack).
|
|
5
|
+
*
|
|
6
|
+
* Posture (decided): block advice *applied to the user's own situation*, but still answer
|
|
7
|
+
* general/building questions. A disclaimer alone is not a defense (UPL law), so the broker
|
|
8
|
+
* short-circuits on a match BEFORE calling the model — same shape as crisis detection.
|
|
9
|
+
*
|
|
10
|
+
* NOTE: the refusal copy + the patterns below are pending review by a licensed attorney
|
|
11
|
+
* and a clinician before live answers are enabled (see the proposal's launch gate).
|
|
12
|
+
*/
|
|
13
|
+
// Each domain matches advice *applied to the user's situation* — not mere topic mentions.
|
|
14
|
+
// "what artifacts document a custody incident" (building) must NOT match; "should I file
|
|
15
|
+
// for custody" (advice) must.
|
|
16
|
+
const PATTERNS = [
|
|
17
|
+
{
|
|
18
|
+
domain: "medical",
|
|
19
|
+
re: /\b(what('?s| is) wrong with (me|my)|should i (take|stop|change) (this )?(med|medication|drug|dose)|what (medication|dose|drug|meds) (should|do) i|diagnos(e|is|ing) (me|my)|is (this|that) (a )?(symptom|condition|disease)|do i have (a )?(condition|disorder|disease)|treat(ment)? for my)\b/i,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
domain: "legal",
|
|
23
|
+
re: /\b(should i (file|sue|settle|sign|appeal|petition|respond)|do i have a (case|claim)|what are my (legal )?rights|is (this|that|it) (legal|illegal|admissible|enforceable)|can i (sue|file|get custody|win)|will i (win|lose|get custody)|how do i (file|serve|appeal|get a restraining order)|is (this|that) (abuse|neglect|contempt|grounds)|what should i (say|do) (in|at) court)\b/i,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
domain: "mental-health",
|
|
27
|
+
re: /\b(am i (depressed|bipolar|anxious|traumatized|ok|crazy|a narcissist)|do i have (ptsd|depression|anxiety|adhd|a disorder)|is my (ex|partner|child|co-?parent) (a narcissist|bipolar|abusive|gaslighting)|should i (be on|take) (medication|antidepressants|therapy)|diagnose (me|my))\b/i,
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
/** Detect a request for advice applied to the user's situation. Conservative by design. */
|
|
31
|
+
export function detectAdviceRequest(text) {
|
|
32
|
+
const t = (text || "").toLowerCase();
|
|
33
|
+
for (const { domain, re } of PATTERNS) {
|
|
34
|
+
if (re.test(t))
|
|
35
|
+
return { matched: true, domain };
|
|
36
|
+
}
|
|
37
|
+
return { matched: false };
|
|
38
|
+
}
|
|
39
|
+
const DOMAIN_LABEL = {
|
|
40
|
+
legal: "legal",
|
|
41
|
+
medical: "medical",
|
|
42
|
+
"mental-health": "mental-health",
|
|
43
|
+
};
|
|
44
|
+
const DOMAIN_ROUTE = {
|
|
45
|
+
legal: "a licensed attorney or your local legal-aid office",
|
|
46
|
+
medical: "a licensed medical professional",
|
|
47
|
+
"mental-health": "a licensed mental-health professional",
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The scoped, non-advice response. Acknowledges, declines the advice, routes to a
|
|
51
|
+
* licensed professional, and keeps the door open for build help. (Copy pending SME review.)
|
|
52
|
+
*/
|
|
53
|
+
export function adviceRefusal(domain, joinUrl) {
|
|
54
|
+
const help = joinUrl ? ` If you're building a tool for this, I'm glad to help with that — see ${joinUrl}.` : " I'm glad to help with building a tool, though.";
|
|
55
|
+
return (`I can't give ${DOMAIN_LABEL[domain]} advice — I'm a build assistant, not a substitute ` +
|
|
56
|
+
`for a professional, and that's a decision for ${DOMAIN_ROUTE[domain]} who knows your ` +
|
|
57
|
+
`situation. I can share general, educational information and point you to the right ` +
|
|
58
|
+
`resources.${help}`);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=compliance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/assistant/compliance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,0FAA0F;AAC1F,yFAAyF;AACzF,8BAA8B;AAC9B,MAAM,QAAQ,GAA2C;IACvD;QACE,MAAM,EAAE,SAAS;QACjB,EAAE,EAAE,iSAAiS;KACtS;IACD;QACE,MAAM,EAAE,OAAO;QACf,EAAE,EAAE,uXAAuX;KAC5X;IACD;QACE,MAAM,EAAE,eAAe;QACvB,EAAE,EAAE,0RAA0R;KAC/R;CACF,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACrC,KAAK,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,QAAQ,EAAE,CAAC;QACtC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,YAAY,GAAiC;IACjD,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,eAAe,EAAE,eAAe;CACjC,CAAC;AAEF,MAAM,YAAY,GAAiC;IACjD,KAAK,EAAE,oDAAoD;IAC3D,OAAO,EAAE,iCAAiC;IAC1C,eAAe,EAAE,uCAAuC;CACzD,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE,OAAgB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,yEAAyE,OAAO,GAAG,CAAC,CAAC,CAAC,iDAAiD,CAAC;IAC/J,OAAO,CACL,gBAAgB,YAAY,CAAC,MAAM,CAAC,oDAAoD;QACxF,iDAAiD,YAAY,CAAC,MAAM,CAAC,kBAAkB;QACvF,qFAAqF;QACrF,aAAa,IAAI,EAAE,CACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crisis detection — the hard-wired safety net shared by every assistant surface
|
|
3
|
+
* (the web widget AND the broker). Dependency-free on purpose so it ships to the
|
|
4
|
+
* browser as-is (copied by the site builder) and runs server-side unchanged.
|
|
5
|
+
*
|
|
6
|
+
* This is NOT a clinical triage tool. It errs toward surfacing help: if the text
|
|
7
|
+
* looks like crisis, the caller MUST lead with resources before any other action.
|
|
8
|
+
* Resources are never gated behind a question.
|
|
9
|
+
*/
|
|
10
|
+
export interface CrisisResource {
|
|
11
|
+
label: string;
|
|
12
|
+
/** Phone number (digits only) for a tel: link. */
|
|
13
|
+
tel?: string;
|
|
14
|
+
/** SMS instruction, e.g. "Text HOME to 741741". */
|
|
15
|
+
sms?: string;
|
|
16
|
+
note: string;
|
|
17
|
+
}
|
|
18
|
+
/** The canonical resource list — same numbers the crisis modal + MCP server use. */
|
|
19
|
+
export declare const CRISIS_RESOURCES: readonly CrisisResource[];
|
|
20
|
+
export type CrisisCategory = "suicidal" | "violence" | "child-safety" | "general";
|
|
21
|
+
export interface CrisisMatch {
|
|
22
|
+
matched: boolean;
|
|
23
|
+
category?: CrisisCategory;
|
|
24
|
+
/** Resources ordered for the matched category (most relevant first). */
|
|
25
|
+
resources: readonly CrisisResource[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Scan free text for crisis signals. Returns the matched category (if any) and
|
|
29
|
+
* the resources to surface. On no match, `matched:false` with an empty list.
|
|
30
|
+
*/
|
|
31
|
+
export declare function detectCrisis(text: string): CrisisMatch;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crisis detection — the hard-wired safety net shared by every assistant surface
|
|
3
|
+
* (the web widget AND the broker). Dependency-free on purpose so it ships to the
|
|
4
|
+
* browser as-is (copied by the site builder) and runs server-side unchanged.
|
|
5
|
+
*
|
|
6
|
+
* This is NOT a clinical triage tool. It errs toward surfacing help: if the text
|
|
7
|
+
* looks like crisis, the caller MUST lead with resources before any other action.
|
|
8
|
+
* Resources are never gated behind a question.
|
|
9
|
+
*/
|
|
10
|
+
/** The canonical resource list — same numbers the crisis modal + MCP server use. */
|
|
11
|
+
export const CRISIS_RESOURCES = [
|
|
12
|
+
{ label: "911", tel: "911", note: "Immediate physical danger" },
|
|
13
|
+
{ label: "988 Suicide & Crisis Lifeline", tel: "988", note: "Call or text, US, 24/7" },
|
|
14
|
+
{ label: "Crisis Text Line", sms: "Text HOME to 741741", note: "Free, 24/7, confidential" },
|
|
15
|
+
{ label: "National Domestic Violence Hotline", tel: "18007997233", note: "1-800-799-7233, 24/7" },
|
|
16
|
+
{ label: "Childhelp National Child Abuse Hotline", tel: "18004224453", note: "1-800-422-4453" },
|
|
17
|
+
];
|
|
18
|
+
const PATTERNS = [
|
|
19
|
+
{
|
|
20
|
+
category: "suicidal",
|
|
21
|
+
re: /\b(kill myself|killing myself|end my life|ending my life|take my (own )?life|want to die|wanna die|don'?t want to (live|be here|be alive)|suicid|hurt myself|harm myself|no reason to live|better off dead)/i,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
category: "child-safety",
|
|
25
|
+
re: /\b(child (abuse|is in danger|being hurt|being abused)|hurt(ing)? (my|the|a) (kid|child|son|daughter|baby)|abus(e|ing) (my|the|a) (kid|child)|my (kid|child) (is|isn'?t) safe)\b/i,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
category: "violence",
|
|
29
|
+
re: /(\b(he|she|they|my (partner|ex|husband|wife)) (hit|hits|beat|beats|strangl|chok|threaten|threatened|attack))|domestic (violence|abuse)|being (abused|beaten|stalked|followed)|afraid (for|of) my (life|safety)|not safe at home|going to (hurt|kill) me/i,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Scan free text for crisis signals. Returns the matched category (if any) and
|
|
34
|
+
* the resources to surface. On no match, `matched:false` with an empty list.
|
|
35
|
+
*/
|
|
36
|
+
export function detectCrisis(text) {
|
|
37
|
+
const t = (text || "").toLowerCase();
|
|
38
|
+
for (const { category, re } of PATTERNS) {
|
|
39
|
+
if (re.test(t))
|
|
40
|
+
return { matched: true, category, resources: orderFor(category) };
|
|
41
|
+
}
|
|
42
|
+
return { matched: false, resources: [] };
|
|
43
|
+
}
|
|
44
|
+
/** Order the canonical resources so the most relevant line leads for a category. */
|
|
45
|
+
function orderFor(category) {
|
|
46
|
+
const by = (label) => CRISIS_RESOURCES.find((r) => r.label.startsWith(label));
|
|
47
|
+
const pick = (...labels) => labels.map(by).filter((r) => Boolean(r));
|
|
48
|
+
switch (category) {
|
|
49
|
+
case "suicidal":
|
|
50
|
+
return [...pick("988", "Crisis Text Line", "911"), ...rest(["988", "Crisis Text Line", "911"])];
|
|
51
|
+
case "violence":
|
|
52
|
+
return [...pick("National Domestic Violence", "911", "988"), ...rest(["National Domestic Violence", "911", "988"])];
|
|
53
|
+
case "child-safety":
|
|
54
|
+
return [...pick("Childhelp", "911", "988"), ...rest(["Childhelp", "911", "988"])];
|
|
55
|
+
default:
|
|
56
|
+
return CRISIS_RESOURCES;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function rest(leadPrefixes) {
|
|
60
|
+
return CRISIS_RESOURCES.filter((r) => !leadPrefixes.some((p) => r.label.startsWith(p)));
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=crisis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crisis.js","sourceRoot":"","sources":["../../src/assistant/crisis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cotrackpro/sdk/assistant — the shared "assistant-core" reused by the web widget
|
|
3
|
+
* and the broker: crisis detection, RBAC tier→tool allowlist, and the guardrail
|
|
4
|
+
* system-prompt composer. Single source of truth so both surfaces enforce the same
|
|
5
|
+
* child-centered, trauma-informed contract.
|
|
6
|
+
*
|
|
7
|
+
* Note: `crisis` and `rbac` are dependency-free and browser-safe; `prompt` imports
|
|
8
|
+
* the catalog taxonomy and is server-only.
|
|
9
|
+
*/
|
|
10
|
+
export * from "./crisis.js";
|
|
11
|
+
export * from "./rbac.js";
|
|
12
|
+
export * from "./prompt.js";
|
|
13
|
+
export * from "./levels.js";
|
|
14
|
+
export * from "./readability.js";
|
|
15
|
+
export * from "./compliance.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cotrackpro/sdk/assistant — the shared "assistant-core" reused by the web widget
|
|
3
|
+
* and the broker: crisis detection, RBAC tier→tool allowlist, and the guardrail
|
|
4
|
+
* system-prompt composer. Single source of truth so both surfaces enforce the same
|
|
5
|
+
* child-centered, trauma-informed contract.
|
|
6
|
+
*
|
|
7
|
+
* Note: `crisis` and `rbac` are dependency-free and browser-safe; `prompt` imports
|
|
8
|
+
* the catalog taxonomy and is server-only.
|
|
9
|
+
*/
|
|
10
|
+
export * from "./crisis.js";
|
|
11
|
+
export * from "./rbac.js";
|
|
12
|
+
export * from "./prompt.js";
|
|
13
|
+
export * from "./levels.js";
|
|
14
|
+
export * from "./readability.js";
|
|
15
|
+
export * from "./compliance.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/assistant/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading-level / age translator bands. People reach this platform under stress and
|
|
3
|
+
* at very different literacy levels — a child, a parent mid-crisis, a professional.
|
|
4
|
+
* A `ReadingLevel` maps to a target US school grade and a prompt directive that tells
|
|
5
|
+
* the model how to write. The substance (and crisis resources) never change — only
|
|
6
|
+
* the wording. Pair with `readability.ts` to verify the output actually hit the band.
|
|
7
|
+
*/
|
|
8
|
+
export type ReadingLevel = "kid" | "preteen" | "teen" | "plain" | "pro";
|
|
9
|
+
export interface ReadingBand {
|
|
10
|
+
id: ReadingLevel;
|
|
11
|
+
label: string;
|
|
12
|
+
/** Target Flesch–Kincaid grade, or null for "professional" (unconstrained). */
|
|
13
|
+
grade: number | null;
|
|
14
|
+
}
|
|
15
|
+
/** The selectable bands, in order. "plain" is the portal's existing default. */
|
|
16
|
+
export declare const READING_BANDS: readonly ReadingBand[];
|
|
17
|
+
export declare const DEFAULT_READING_LEVEL: ReadingLevel;
|
|
18
|
+
/** Coerce arbitrary input to a known level (defaults to "plain"). */
|
|
19
|
+
export declare function asReadingLevel(v: unknown): ReadingLevel;
|
|
20
|
+
/**
|
|
21
|
+
* Detect a reading-level request phrased in natural language (for surfaces without a
|
|
22
|
+
* selector, e.g. the Slack agent: "explain for a 10-year-old", "in plain English").
|
|
23
|
+
* Returns undefined when there's no hint.
|
|
24
|
+
*/
|
|
25
|
+
export declare function detectReadingLevel(text: string): ReadingLevel | undefined;
|
|
26
|
+
/** Target grade for a level (null = professional / unconstrained). */
|
|
27
|
+
export declare function targetGradeFor(level: ReadingLevel): number | null;
|
|
28
|
+
/**
|
|
29
|
+
* The system-prompt directive for a level. For graded levels it constrains wording
|
|
30
|
+
* but explicitly preserves safety meaning + crisis resources; "pro" allows precise
|
|
31
|
+
* terminology. "plain" returns "" — it's the baseline the prompt already targets.
|
|
32
|
+
*/
|
|
33
|
+
export declare function readingLevelDirective(level: ReadingLevel): string;
|
|
34
|
+
/** Ordered band ids, simplest → most technical. */
|
|
35
|
+
export declare const LEVEL_ORDER: readonly ReadingLevel[];
|
|
36
|
+
/** The next, more-technical level (or the same when already at the top). */
|
|
37
|
+
export declare function nextLevel(level: ReadingLevel): ReadingLevel;
|
|
38
|
+
/** The previous, simpler level (or the same when already at the bottom). */
|
|
39
|
+
export declare function prevLevel(level: ReadingLevel): ReadingLevel;
|
|
40
|
+
/** True when there's a more-technical level to grow into. */
|
|
41
|
+
export declare function canLevelUp(level: ReadingLevel): boolean;
|
|
42
|
+
/** Human label for a level id. */
|
|
43
|
+
export declare function levelLabel(level: ReadingLevel): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** The selectable bands, in order. "plain" is the portal's existing default. */
|
|
2
|
+
export const READING_BANDS = [
|
|
3
|
+
{ id: "kid", label: "Kid", grade: 3 },
|
|
4
|
+
{ id: "preteen", label: "Pre-teen", grade: 5 },
|
|
5
|
+
{ id: "teen", label: "Teen", grade: 7 },
|
|
6
|
+
{ id: "plain", label: "Plain", grade: 8 },
|
|
7
|
+
{ id: "pro", label: "Professional", grade: null },
|
|
8
|
+
];
|
|
9
|
+
const BY_ID = Object.fromEntries(READING_BANDS.map((b) => [b.id, b]));
|
|
10
|
+
export const DEFAULT_READING_LEVEL = "plain";
|
|
11
|
+
/** Coerce arbitrary input to a known level (defaults to "plain"). */
|
|
12
|
+
export function asReadingLevel(v) {
|
|
13
|
+
return typeof v === "string" && v in BY_ID ? v : DEFAULT_READING_LEVEL;
|
|
14
|
+
}
|
|
15
|
+
/** Map a US grade number to the nearest band. */
|
|
16
|
+
function bandForGrade(grade) {
|
|
17
|
+
if (grade <= 3)
|
|
18
|
+
return "kid";
|
|
19
|
+
if (grade <= 5)
|
|
20
|
+
return "preteen";
|
|
21
|
+
if (grade <= 7)
|
|
22
|
+
return "teen";
|
|
23
|
+
return "plain";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Detect a reading-level request phrased in natural language (for surfaces without a
|
|
27
|
+
* selector, e.g. the Slack agent: "explain for a 10-year-old", "in plain English").
|
|
28
|
+
* Returns undefined when there's no hint.
|
|
29
|
+
*/
|
|
30
|
+
export function detectReadingLevel(text) {
|
|
31
|
+
const t = (text || "").toLowerCase();
|
|
32
|
+
const gradeM = t.match(/\bgrade[- ]?(\d{1,2})\b/) || t.match(/\b(\d{1,2})(?:st|nd|rd|th)[- ]?grade\b/);
|
|
33
|
+
if (gradeM)
|
|
34
|
+
return bandForGrade(Number(gradeM[1]));
|
|
35
|
+
const ageM = t.match(/\b(?:i'?m|i am|like i'?m|for a|for an|year[- ]?old|aged?)\D{0,12}?(\d{1,2})\b/);
|
|
36
|
+
if (ageM && /year|old|i'?m|i am|aged?|for a/.test(t)) {
|
|
37
|
+
const age = Number(ageM[1]);
|
|
38
|
+
if (age <= 8)
|
|
39
|
+
return "kid";
|
|
40
|
+
if (age <= 11)
|
|
41
|
+
return "preteen";
|
|
42
|
+
if (age <= 17)
|
|
43
|
+
return "teen";
|
|
44
|
+
}
|
|
45
|
+
if (/\b(for|like)\b.{0,12}\b(kid|child|young child|little (kid|one))\b/.test(t))
|
|
46
|
+
return "kid";
|
|
47
|
+
if (/\b(pre-?teen|tween)\b/.test(t))
|
|
48
|
+
return "preteen";
|
|
49
|
+
if (/\b(teen|teenager|high ?school)\b/.test(t))
|
|
50
|
+
return "teen";
|
|
51
|
+
if (/\b(plain|simple) (english|language|terms|words)\b|\bsimply\b|\bin plain\b/.test(t))
|
|
52
|
+
return "plain";
|
|
53
|
+
if (/\b(lawyer|attorney|professional|clinician|technical|be precise|precise terms)\b/.test(t))
|
|
54
|
+
return "pro";
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/** Target grade for a level (null = professional / unconstrained). */
|
|
58
|
+
export function targetGradeFor(level) {
|
|
59
|
+
return BY_ID[level]?.grade ?? null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The system-prompt directive for a level. For graded levels it constrains wording
|
|
63
|
+
* but explicitly preserves safety meaning + crisis resources; "pro" allows precise
|
|
64
|
+
* terminology. "plain" returns "" — it's the baseline the prompt already targets.
|
|
65
|
+
*/
|
|
66
|
+
export function readingLevelDirective(level) {
|
|
67
|
+
if (level === "plain")
|
|
68
|
+
return "";
|
|
69
|
+
if (level === "pro") {
|
|
70
|
+
return "Audience: professionals (attorneys, GALs, clinicians). Precise legal and clinical terminology is fine; be exact and concise.";
|
|
71
|
+
}
|
|
72
|
+
const grade = targetGradeFor(level);
|
|
73
|
+
return [
|
|
74
|
+
`Write at a US grade-${grade} reading level: short sentences (mostly under 12 words)`,
|
|
75
|
+
`and everyday words. This reader is LEARNING the technical material, so teach as you go:`,
|
|
76
|
+
`explain each idea in plain words first, then introduce the correct technical term in`,
|
|
77
|
+
`parentheses (e.g. "a saved record (an 'artifact')") so their vocabulary grows and they`,
|
|
78
|
+
`can level up. Keep ALL safety meaning intact and reproduce any crisis resources exactly`,
|
|
79
|
+
`— never simplify those away. Change the wording, never the meaning.`,
|
|
80
|
+
].join(" ");
|
|
81
|
+
}
|
|
82
|
+
/** Ordered band ids, simplest → most technical. */
|
|
83
|
+
export const LEVEL_ORDER = READING_BANDS.map((b) => b.id);
|
|
84
|
+
/** The next, more-technical level (or the same when already at the top). */
|
|
85
|
+
export function nextLevel(level) {
|
|
86
|
+
const i = LEVEL_ORDER.indexOf(level);
|
|
87
|
+
return (i >= 0 ? LEVEL_ORDER[i + 1] : undefined) ?? level;
|
|
88
|
+
}
|
|
89
|
+
/** The previous, simpler level (or the same when already at the bottom). */
|
|
90
|
+
export function prevLevel(level) {
|
|
91
|
+
const i = LEVEL_ORDER.indexOf(level);
|
|
92
|
+
return (i > 0 ? LEVEL_ORDER[i - 1] : undefined) ?? level;
|
|
93
|
+
}
|
|
94
|
+
/** True when there's a more-technical level to grow into. */
|
|
95
|
+
export function canLevelUp(level) {
|
|
96
|
+
return level !== LEVEL_ORDER[LEVEL_ORDER.length - 1];
|
|
97
|
+
}
|
|
98
|
+
/** Human label for a level id. */
|
|
99
|
+
export function levelLabel(level) {
|
|
100
|
+
return BY_ID[level]?.label ?? level;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=levels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"levels.js","sourceRoot":"","sources":["../../src/assistant/levels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AssistantTier } from "./rbac.js";
|
|
2
|
+
import { type ReadingLevel } from "./levels.js";
|
|
3
|
+
export interface SystemPromptOptions {
|
|
4
|
+
tier: AssistantTier;
|
|
5
|
+
/** The portal page the user is on, for context-aware help (e.g. "catalog"). */
|
|
6
|
+
page?: string;
|
|
7
|
+
/** Tool names the broker will actually expose this turn (from the allowlist). */
|
|
8
|
+
allowedTools: readonly string[];
|
|
9
|
+
/** Target reading level for the answer (the age/grade translator). */
|
|
10
|
+
readingLevel?: ReadingLevel;
|
|
11
|
+
/**
|
|
12
|
+
* What the turn is for. "ask" (default) is the normal Q&A copilot. "rewrite" re-tones
|
|
13
|
+
* a page's existing copy to the reading level without changing its meaning — the broker
|
|
14
|
+
* passes the page text as the user turn. The guardrails (crisis-first, advice-refusal,
|
|
15
|
+
* the child-centered lens) are identical for both.
|
|
16
|
+
*/
|
|
17
|
+
intent?: "ask" | "rewrite";
|
|
18
|
+
}
|
|
19
|
+
/** Build the full system prompt for one turn, grounded in the live guardrails. */
|
|
20
|
+
export declare function buildSystemPrompt(opts: SystemPromptOptions): string;
|