@rsconcept/rstool 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/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +585 -0
- package/dist/index.js.map +1 -0
- package/dist/mappers/model-adapter.d.ts +27 -0
- package/dist/mappers/model-adapter.js +248 -0
- package/dist/mappers/model-adapter.js.map +1 -0
- package/dist/mappers/schema-adapter.d.ts +22 -0
- package/dist/mappers/schema-adapter.js +89 -0
- package/dist/mappers/schema-adapter.js.map +1 -0
- package/dist/mappers/types.d.ts +23 -0
- package/dist/mappers/types.js +22 -0
- package/dist/mappers/types.js.map +1 -0
- package/dist/models/analysis.d.ts +18 -0
- package/dist/models/analysis.js +1 -0
- package/dist/models/analysis.js.map +1 -0
- package/dist/models/common.d.ts +15 -0
- package/dist/models/common.js +12 -0
- package/dist/models/common.js.map +1 -0
- package/dist/models/constituenta.d.ts +38 -0
- package/dist/models/constituenta.js +1 -0
- package/dist/models/constituenta.js.map +1 -0
- package/dist/models/diagnostic.d.ts +17 -0
- package/dist/models/diagnostic.js +1 -0
- package/dist/models/diagnostic.js.map +1 -0
- package/dist/models/evaluation.d.ts +23 -0
- package/dist/models/evaluation.js +1 -0
- package/dist/models/evaluation.js.map +1 -0
- package/dist/models/index.d.ts +13 -0
- package/dist/models/index.js +491 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/model-value.d.ts +37 -0
- package/dist/models/model-value.js +1 -0
- package/dist/models/model-value.js.map +1 -0
- package/dist/models/rstool-agent.d.ts +36 -0
- package/dist/models/rstool-agent.js +480 -0
- package/dist/models/rstool-agent.js.map +1 -0
- package/dist/models/session.d.ts +29 -0
- package/dist/models/session.js +1 -0
- package/dist/models/session.js.map +1 -0
- package/dist/models/tool-contract.d.ts +33 -0
- package/dist/models/tool-contract.js +6 -0
- package/dist/models/tool-contract.js.map +1 -0
- package/dist/session/session-store.d.ts +26 -0
- package/dist/session/session-store.js +66 -0
- package/dist/session/session-store.js.map +1 -0
- package/dist/wrapper/client.d.ts +30 -0
- package/dist/wrapper/client.js +96 -0
- package/dist/wrapper/client.js.map +1 -0
- package/dist/wrapper/stdio-wrapper.d.ts +1 -0
- package/dist/wrapper/stdio-wrapper.js +679 -0
- package/dist/wrapper/stdio-wrapper.js.map +1 -0
- package/docs/CONSTITUENTA.md +55 -0
- package/docs/DIAGNOSTICS.md +125 -0
- package/docs/DOMAIN.md +89 -0
- package/docs/GRAMMAR-REF.md +98 -0
- package/docs/PORTAL-API.md +48 -0
- package/docs/README.md +15 -0
- package/docs/SYNTAX.md +139 -0
- package/docs/TYPIFICATION.md +79 -0
- package/package.json +76 -0
- package/skills/README.md +15 -0
- package/skills/rstool-helper/EXAMPLES.md +154 -0
- package/skills/rstool-helper/REFERENCE.md +169 -0
- package/skills/rstool-helper/SKILL.md +148 -0
- package/src/index.ts +43 -0
- package/src/mappers/model-adapter.ts +276 -0
- package/src/mappers/schema-adapter.ts +87 -0
- package/src/mappers/types.ts +35 -0
- package/src/models/analysis.ts +13 -0
- package/src/models/common.ts +17 -0
- package/src/models/constituenta.ts +35 -0
- package/src/models/diagnostic.ts +12 -0
- package/src/models/evaluation.ts +25 -0
- package/src/models/index.ts +33 -0
- package/src/models/model-value.ts +31 -0
- package/src/models/rstool-agent.test.ts +300 -0
- package/src/models/rstool-agent.ts +143 -0
- package/src/models/session.ts +22 -0
- package/src/models/tool-contract.ts +47 -0
- package/src/session/session-store.ts +81 -0
- package/src/wrapper/client.ts +116 -0
- package/src/wrapper/stdio-wrapper.ts +225 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rstool-helper
|
|
3
|
+
description: RS language and @rsconcept/rstool for AI agents: incremental RSForm construction, formal definitions, typification, diagnostics, modeling, evaluation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RS Language & rstool — Compact Guide for Agents
|
|
7
|
+
|
|
8
|
+
**RS language** is a formal scheme notation for concepts, relations, operations—extends FOL, core: membership `x∈y`; typification via set-theoretic/logical expressions.
|
|
9
|
+
|
|
10
|
+
**rstool** is the agent API for sessions, upserts, analysis, diagnostics, modeling/evaluation, (de)serialization.
|
|
11
|
+
|
|
12
|
+
- Library: `@rsconcept/rstool` (npm)
|
|
13
|
+
- Analyzer: `@rsconcept/domain` (installed automatically as a dependency)
|
|
14
|
+
- Language and API reference: bundled `docs/*.md` copied into this skill during installation
|
|
15
|
+
|
|
16
|
+
## Installing This Skill
|
|
17
|
+
|
|
18
|
+
After installing the package in an agent project:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @rsconcept/rstool
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
copy the skill into your agent host's skill directory.
|
|
25
|
+
|
|
26
|
+
Cursor per-project skills:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mkdir -p .agents/skills
|
|
30
|
+
cp -R node_modules/@rsconcept/rstool/skills/rstool-helper .agents/skills/rstool-helper
|
|
31
|
+
cp -R node_modules/@rsconcept/rstool/docs .agents/skills/rstool-helper/docs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
PowerShell:
|
|
35
|
+
|
|
36
|
+
```powershell
|
|
37
|
+
New-Item -ItemType Directory -Force .agents/skills
|
|
38
|
+
Copy-Item -Recurse -Force node_modules/@rsconcept/rstool/skills/rstool-helper .agents/skills/rstool-helper
|
|
39
|
+
Copy-Item -Recurse -Force node_modules/@rsconcept/rstool/docs .agents/skills/rstool-helper/docs
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This makes the skill self-contained for hosts that only read files under the skill directory.
|
|
43
|
+
|
|
44
|
+
## Docs/Hints Reference
|
|
45
|
+
|
|
46
|
+
| Info | Location |
|
|
47
|
+
| :---------------------------------------- | :---------------------------------------------------------------- |
|
|
48
|
+
| rstool API, methods, error codes | [REFERENCE.md](REFERENCE.md) |
|
|
49
|
+
| Worked examples, common mistakes | [EXAMPLES.md](EXAMPLES.md) |
|
|
50
|
+
| Domain vocabulary (English) | `docs/DOMAIN.md` (bundled with the npm package) |
|
|
51
|
+
| Constituenta fields, validation, ordering | `docs/CONSTITUENTA.md` |
|
|
52
|
+
| RSLang syntax (operators, quantifiers) | `docs/SYNTAX.md` |
|
|
53
|
+
| Typification grades, radicals | `docs/TYPIFICATION.md` |
|
|
54
|
+
| Diagnostic code → fix table | `docs/DIAGNOSTICS.md` |
|
|
55
|
+
| Portal REST API (live data) | `docs/PORTAL-API.md` |
|
|
56
|
+
| Lezer grammar pointers | `docs/GRAMMAR-REF.md` (full grammar lives in `@rsconcept/domain`) |
|
|
57
|
+
| Code samples | [EXAMPLES.md](EXAMPLES.md), package README |
|
|
58
|
+
|
|
59
|
+
If you installed `@rsconcept/rstool` from npm, the source docs ship inside `node_modules/@rsconcept/rstool/docs/`; the install commands above copy them into this skill folder.
|
|
60
|
+
|
|
61
|
+
## Protocol Summary
|
|
62
|
+
|
|
63
|
+
1. **Start session**: `createSession`
|
|
64
|
+
2. **Add bases/constants**: type `basic` (`X*`), `constant` (`C*`) — `definitionFormal: ''`
|
|
65
|
+
3. **Add derived**: terms, axioms, etc.—only after dependencies present
|
|
66
|
+
4. **Analyze scratch**: `analyzeExpression`
|
|
67
|
+
5. **Process diagnostics**: check `analysis.diagnostics`/`listDiagnostics`; fix by range
|
|
68
|
+
6. **Checkpoint**: `commitStep` (message optional)
|
|
69
|
+
7. **Model values**: `setConstituentaValue` / `setConstituentaValues` for base bindings (`{0:"a",1:"b"}`) or structured values; `getModelState`
|
|
70
|
+
8. **Evaluate**: `evaluateExpression` (scratch) or `evaluateConstituenta` / `recalculateModel` (stored definitions)
|
|
71
|
+
9. **Export/import**: persist with `exportSession`/`importSession` (includes `state.model`)
|
|
72
|
+
|
|
73
|
+
**Clients**:
|
|
74
|
+
|
|
75
|
+
- Node: use `RSToolWrapperClient`
|
|
76
|
+
- Stdio process: `npx rstool-wrapper` — JSON per line
|
|
77
|
+
|
|
78
|
+
## API/REST
|
|
79
|
+
|
|
80
|
+
For full reference see `docs/PORTAL-API.md`. Short form:
|
|
81
|
+
|
|
82
|
+
- **Portal UI**: `https://portal.acconcept.ru`
|
|
83
|
+
- **API**: `https://api.portal.acconcept.ru`
|
|
84
|
+
- Endpoints: `GET /api/rsforms/{id}`, `GET /api/rsforms/{id}/details`, `GET /api/library/{id}/versions/{v}`, `GET /api/oss/{id}`, `GET /api/models/{id}`, OpenAPI at `GET /schema`.
|
|
85
|
+
- Don't scrape SPA or use UI query params (`tab=`, etc.).
|
|
86
|
+
- rstool itself never calls the REST API; bring data in via `addOrUpdateConstituenta` after fetching.
|
|
87
|
+
|
|
88
|
+
## Constituent Types (`cstType`)
|
|
89
|
+
|
|
90
|
+
| cstType | Example | Formal | Notes |
|
|
91
|
+
| :-------- | :------ | :-------- | :------------------- |
|
|
92
|
+
| basic | X1 | **empty** | Required |
|
|
93
|
+
| constant | C1 | **empty** | Required |
|
|
94
|
+
| nominal | S1 | allowed | Naming |
|
|
95
|
+
| structure | custom | allowed | Structured genus |
|
|
96
|
+
| term | D1 | allowed | Set/term |
|
|
97
|
+
| axiom | A1 | allowed | Logical (type=Logic) |
|
|
98
|
+
| statement | T1 | allowed | Logical (type=Logic) |
|
|
99
|
+
| function | F1 | allowed | Parameterized |
|
|
100
|
+
| predicate | P1 | allowed | Parameterized |
|
|
101
|
+
|
|
102
|
+
- Non-empty formal for `basic`/`constant` ⇒ error `0x8862` (`definitionNotAllowed`)
|
|
103
|
+
- Empty `basic`/`constant` always typified
|
|
104
|
+
- **Interpretable** (can set value): `basic`, `constant`, `structure`, `axiom`, `term`, `statement`
|
|
105
|
+
- **Inferrable** (computed, do not set directly): `term`, `axiom`, `statement`
|
|
106
|
+
|
|
107
|
+
## Syntax
|
|
108
|
+
|
|
109
|
+
- **Globals**: `X1`, `C1`, `D1`, `F1`, `P1`, `A1`, `R1`
|
|
110
|
+
- **Locals**: `x`, `ξ`, `μ2`
|
|
111
|
+
- **Literals**: `42`, `Z`, `∅`
|
|
112
|
+
- Full operator + precedence table: `docs/SYNTAX.md`
|
|
113
|
+
- Grammar pointers: `docs/GRAMMAR-REF.md`
|
|
114
|
+
|
|
115
|
+
## Expression Types
|
|
116
|
+
|
|
117
|
+
- **Set-theoretic**: `∪`, `∩`, `\`, `∆`, `×`, `∈`, `⊆`, `ℬ(...)`, tuples
|
|
118
|
+
- **Logical**: `¬`, `&`, `∨`, `⇒`, `⇔`, `∀`, `∃`, comparisons `=`, `≠`, `<`
|
|
119
|
+
- **Parameterized**: `[arg1∈H1, arg2∈H2] body`
|
|
120
|
+
- Detailed semantics in `docs/SYNTAX.md`; typification grades and radicals in `docs/TYPIFICATION.md`.
|
|
121
|
+
|
|
122
|
+
Always set `cstType` in upserts/analysis to true role.
|
|
123
|
+
|
|
124
|
+
## Diagnostics Loop
|
|
125
|
+
|
|
126
|
+
1. Check `analysis.success`
|
|
127
|
+
2. If not, see `analysis.diagnostics` / `listDiagnostics`
|
|
128
|
+
3. Map `code` → cause → fix via `docs/DIAGNOSTICS.md`
|
|
129
|
+
4. Use `from`, `to` to patch `definitionFormal`; re-send
|
|
130
|
+
|
|
131
|
+
Don’t infer types—always read tool output.
|
|
132
|
+
|
|
133
|
+
## Declaration Order
|
|
134
|
+
|
|
135
|
+
1. All `basic`, `constant`
|
|
136
|
+
2. Core/critical first
|
|
137
|
+
3. Topological: dependencies before dependents (e.g. `D1` before `D2` if `D2` refers to `D1`)
|
|
138
|
+
4. Derived right after their sources
|
|
139
|
+
|
|
140
|
+
## Checklist
|
|
141
|
+
|
|
142
|
+
- [ ] `sessionId` obtained & tracked
|
|
143
|
+
- [ ] Bases/constants are empty formal
|
|
144
|
+
- [ ] All dependencies exist before upsert
|
|
145
|
+
- [ ] Matching `cstType`
|
|
146
|
+
- [ ] Diagnostics handled before commit/export
|
|
147
|
+
- [ ] Base bindings set before evaluating expressions that reference base elements
|
|
148
|
+
- [ ] For other details, check help topics or [REFERENCE.md](REFERENCE.md)
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export {
|
|
2
|
+
toPublicAnalysis,
|
|
3
|
+
toPublicError,
|
|
4
|
+
type DomainAnalysisLike,
|
|
5
|
+
type DomainErrorLike
|
|
6
|
+
} from './mappers/types';
|
|
7
|
+
export {
|
|
8
|
+
CONTRACT_VERSION,
|
|
9
|
+
CstType,
|
|
10
|
+
EvalStatus,
|
|
11
|
+
RSErrorCode,
|
|
12
|
+
RSToolAgent,
|
|
13
|
+
ValueClass,
|
|
14
|
+
type AddOrUpdateConstituentaInput,
|
|
15
|
+
type AddOrUpdateConstituentaResult,
|
|
16
|
+
type AnalysisResult,
|
|
17
|
+
type AnalyzeExpressionInput,
|
|
18
|
+
type BasicBinding,
|
|
19
|
+
type ClearConstituentaValuesInput,
|
|
20
|
+
type ConstituentaDraft,
|
|
21
|
+
type ConstituentaState,
|
|
22
|
+
type DiagnosticRecord,
|
|
23
|
+
type EvaluateConstituentaInput,
|
|
24
|
+
type EvaluateExpressionInput,
|
|
25
|
+
type EvaluationResult,
|
|
26
|
+
type ListDiagnosticsFilters,
|
|
27
|
+
type ModelValueState,
|
|
28
|
+
type RecalculateModelResult,
|
|
29
|
+
type RSToolAgentContract,
|
|
30
|
+
type RSToolErrorDescription,
|
|
31
|
+
type RSToolValue,
|
|
32
|
+
type SessionHandle,
|
|
33
|
+
type SessionModelState,
|
|
34
|
+
type SessionRevision,
|
|
35
|
+
type SessionState,
|
|
36
|
+
type SetConstituentaValueInput,
|
|
37
|
+
type SetConstituentaValuesInput
|
|
38
|
+
} from './models';
|
|
39
|
+
export {
|
|
40
|
+
RSToolWrapperClient,
|
|
41
|
+
type RSToolWrapperClientOptions,
|
|
42
|
+
type WrapperResponse
|
|
43
|
+
} from './wrapper/client';
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { Graph } from '@rsconcept/domain/graph/graph';
|
|
2
|
+
import { extractGlobals } from '@rsconcept/domain/rslang/api';
|
|
3
|
+
import { type ExpressionType, RSLangAnalyzer, type Value, type ValueClass } from '@rsconcept/domain/rslang';
|
|
4
|
+
import { isBaseSet } from '@rsconcept/domain/library/rsform-api';
|
|
5
|
+
import { type Constituenta, CstType, type RSForm } from '@rsconcept/domain/library/rsform';
|
|
6
|
+
import { RSEngine, type RSEngineServices } from '@rsconcept/domain/library/rsengine';
|
|
7
|
+
import { type BasicBinding, EvalStatus, type RSModel } from '@rsconcept/domain/library/rsmodel';
|
|
8
|
+
import {
|
|
9
|
+
isInferrable,
|
|
10
|
+
isInterpretable,
|
|
11
|
+
toBasicBinding,
|
|
12
|
+
validateBasicBindingData,
|
|
13
|
+
validateValueData
|
|
14
|
+
} from '@rsconcept/domain/library/rsmodel-api';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
type ConstituentaState,
|
|
18
|
+
type EvaluationResult,
|
|
19
|
+
type RecalculateModelResult,
|
|
20
|
+
type SessionModelState,
|
|
21
|
+
type SessionState,
|
|
22
|
+
type SetConstituentaValueInput
|
|
23
|
+
} from '../models';
|
|
24
|
+
import { toPublicError } from './types';
|
|
25
|
+
|
|
26
|
+
const SESSION_MODEL_ID = 0;
|
|
27
|
+
|
|
28
|
+
export class ModelAdapter {
|
|
29
|
+
public async setConstituentaValue(
|
|
30
|
+
session: SessionState,
|
|
31
|
+
input: SetConstituentaValueInput
|
|
32
|
+
): Promise<SessionModelState> {
|
|
33
|
+
this.validateSetInput(session, input);
|
|
34
|
+
const engine = this.createEngine(session);
|
|
35
|
+
const cst = session.items.find(item => item.id === input.target)!;
|
|
36
|
+
const frontendType = cst.cstType;
|
|
37
|
+
|
|
38
|
+
if (isBaseSet(frontendType)) {
|
|
39
|
+
const binding = toBasicBinding(input.value as Record<string | number, string>);
|
|
40
|
+
await engine.setBasicValue(input.target, binding);
|
|
41
|
+
} else {
|
|
42
|
+
await engine.setStructureValue(input.target, input.value as Value);
|
|
43
|
+
}
|
|
44
|
+
session.updatedAt = new Date().toISOString();
|
|
45
|
+
return structuredClone(session.model);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async setConstituentaValues(
|
|
49
|
+
session: SessionState,
|
|
50
|
+
input: { items: SetConstituentaValueInput[] }
|
|
51
|
+
): Promise<SessionModelState> {
|
|
52
|
+
for (const item of input.items) {
|
|
53
|
+
await this.setConstituentaValue(session, item);
|
|
54
|
+
}
|
|
55
|
+
return structuredClone(session.model);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public async clearConstituentaValues(session: SessionState, ids: number[]): Promise<SessionModelState> {
|
|
59
|
+
const engine = this.createEngine(session);
|
|
60
|
+
for (const id of ids) {
|
|
61
|
+
await engine.resetValue(id);
|
|
62
|
+
session.updatedAt = new Date().toISOString();
|
|
63
|
+
}
|
|
64
|
+
return structuredClone(session.model);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public evaluateExpression(session: SessionState, expression: string, cstType: CstType): EvaluationResult {
|
|
68
|
+
const engine = this.createEngine(session);
|
|
69
|
+
const result = engine.evaluateExpression(expression, cstType);
|
|
70
|
+
const status =
|
|
71
|
+
result.value === null
|
|
72
|
+
? result.errors.length > 0
|
|
73
|
+
? EvalStatus.EVAL_FAIL
|
|
74
|
+
: EvalStatus.EMPTY
|
|
75
|
+
: EvalStatus.HAS_DATA;
|
|
76
|
+
return toPublicEvaluationResult(result.value, result.errors, result.iterations, result.cacheHits, status);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public evaluateConstituenta(session: SessionState, constituentId: number): EvaluationResult {
|
|
80
|
+
const cst = session.items.find(item => item.id === constituentId);
|
|
81
|
+
if (!cst) {
|
|
82
|
+
throw new Error(`Unknown constituent: ${constituentId}`);
|
|
83
|
+
}
|
|
84
|
+
const engine = this.createEngine(session);
|
|
85
|
+
const result = engine.calculateCst(constituentId);
|
|
86
|
+
const status = engine.getCstStatus(constituentId);
|
|
87
|
+
return toPublicEvaluationResult(result.value, result.errors, result.iterations, result.cacheHits, status);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public recalculateModel(session: SessionState): RecalculateModelResult {
|
|
91
|
+
const engine = this.createEngine(session);
|
|
92
|
+
engine.recalculateAll();
|
|
93
|
+
const items = session.items.map(item => ({
|
|
94
|
+
id: item.id,
|
|
95
|
+
alias: item.alias,
|
|
96
|
+
value: engine.getCstValue(item.id) as number | number[] | null,
|
|
97
|
+
status: engine.getCstStatus(item.id)
|
|
98
|
+
}));
|
|
99
|
+
return { items };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public createEngine(session: SessionState): RSEngine {
|
|
103
|
+
const schema = buildRSFormFromSession(session);
|
|
104
|
+
const model = buildRSModelFromSession(session);
|
|
105
|
+
const engine = new RSEngine(SESSION_MODEL_ID, createInMemoryServices(session));
|
|
106
|
+
engine.loadData(schema, model);
|
|
107
|
+
return engine;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private validateSetInput(session: SessionState, input: SetConstituentaValueInput): void {
|
|
111
|
+
const cst = session.items.find(item => item.id === input.target);
|
|
112
|
+
if (!cst) {
|
|
113
|
+
throw new Error(`Unknown constituent: ${input.target}`);
|
|
114
|
+
}
|
|
115
|
+
const frontendType = cst.cstType;
|
|
116
|
+
if (!isInterpretable(frontendType)) {
|
|
117
|
+
throw new Error(`Constituent ${cst.alias} is not interpretable`);
|
|
118
|
+
}
|
|
119
|
+
if (isInferrable(frontendType)) {
|
|
120
|
+
throw new Error(`Constituent ${cst.alias} is inferrable and cannot be set directly`);
|
|
121
|
+
}
|
|
122
|
+
if (isBaseSet(frontendType)) {
|
|
123
|
+
if (!validateBasicBindingData(input.value)) {
|
|
124
|
+
throw new Error(`Invalid basic binding for ${cst.alias}`);
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!validateValueData(input.value)) {
|
|
129
|
+
throw new Error(`Invalid structured value for ${cst.alias}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function createInMemoryServices(session: SessionState): RSEngineServices {
|
|
135
|
+
return {
|
|
136
|
+
setCstValue: async ({ data }) => {
|
|
137
|
+
for (const item of data) {
|
|
138
|
+
const entry = {
|
|
139
|
+
id: item.target,
|
|
140
|
+
type: item.type,
|
|
141
|
+
value: item.data as Value | BasicBinding
|
|
142
|
+
};
|
|
143
|
+
const index = session.model.items.findIndex(existing => existing.id === item.target);
|
|
144
|
+
if (index === -1) {
|
|
145
|
+
session.model.items.push(entry);
|
|
146
|
+
} else {
|
|
147
|
+
session.model.items[index] = entry;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
clearValues: async ({ data }) => {
|
|
152
|
+
const ids = new Set(data.items);
|
|
153
|
+
session.model.items = session.model.items.filter(item => !ids.has(item.id));
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function buildRSFormFromSession(session: SessionState): RSForm {
|
|
159
|
+
const graph = new Graph<number>();
|
|
160
|
+
const cstByAlias = new Map<string, Constituenta>();
|
|
161
|
+
const cstByID = new Map<number, Constituenta>();
|
|
162
|
+
const analyzer = new RSLangAnalyzer();
|
|
163
|
+
|
|
164
|
+
const items = session.items.map(item => {
|
|
165
|
+
const cst = toFrontendConstituenta(item);
|
|
166
|
+
cstByAlias.set(cst.alias, cst);
|
|
167
|
+
cstByID.set(cst.id, cst);
|
|
168
|
+
graph.addNode(cst.id);
|
|
169
|
+
if (item.cstType === CstType.BASE) {
|
|
170
|
+
analyzer.addBase(cst.alias);
|
|
171
|
+
}
|
|
172
|
+
if (cst.effectiveType) {
|
|
173
|
+
analyzer.setGlobal(cst.alias, cst.effectiveType, cst.analysis.valueClass as ValueClass | null);
|
|
174
|
+
}
|
|
175
|
+
return cst;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
for (const cst of items) {
|
|
179
|
+
for (const alias of extractGlobals(cst.definition_formal)) {
|
|
180
|
+
const source = cstByAlias.get(alias);
|
|
181
|
+
if (source) {
|
|
182
|
+
graph.addEdge(source.id, cst.id);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
id: 0,
|
|
189
|
+
items,
|
|
190
|
+
cstByAlias,
|
|
191
|
+
cstByID,
|
|
192
|
+
graph,
|
|
193
|
+
analyzer,
|
|
194
|
+
inheritance: [],
|
|
195
|
+
attribution: [],
|
|
196
|
+
attribution_graph: graph.clone(),
|
|
197
|
+
oss: [],
|
|
198
|
+
models: [],
|
|
199
|
+
editors: [],
|
|
200
|
+
versions: [],
|
|
201
|
+
is_produced: false,
|
|
202
|
+
is_attributive: false,
|
|
203
|
+
version: 'latest'
|
|
204
|
+
} as unknown as RSForm;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function buildRSModelFromSession(session: SessionState): RSModel {
|
|
208
|
+
return {
|
|
209
|
+
id: SESSION_MODEL_ID,
|
|
210
|
+
schema: 0,
|
|
211
|
+
editors: [],
|
|
212
|
+
items: session.model.items.map(item => ({
|
|
213
|
+
id: item.id,
|
|
214
|
+
type: item.type,
|
|
215
|
+
value: item.value as Value | BasicBinding
|
|
216
|
+
}))
|
|
217
|
+
} as unknown as RSModel;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function toFrontendConstituenta(item: ConstituentaState): Constituenta {
|
|
221
|
+
const effectiveType = (item.analysis.type ?? null) as ExpressionType | null;
|
|
222
|
+
return {
|
|
223
|
+
id: item.id,
|
|
224
|
+
alias: item.alias,
|
|
225
|
+
cst_type: item.cstType,
|
|
226
|
+
definition_formal: item.definitionFormal,
|
|
227
|
+
definition_raw: item.definitionFormal,
|
|
228
|
+
definition_resolved: item.definitionFormal,
|
|
229
|
+
term_raw: item.term,
|
|
230
|
+
term_resolved: item.term,
|
|
231
|
+
term_forms: [],
|
|
232
|
+
convention: item.convention,
|
|
233
|
+
typification_manual: '',
|
|
234
|
+
value_is_property: false,
|
|
235
|
+
crucial: false,
|
|
236
|
+
attributes: [],
|
|
237
|
+
homonyms: [],
|
|
238
|
+
formalDuplicates: [],
|
|
239
|
+
analysis: {
|
|
240
|
+
success: item.analysis.success,
|
|
241
|
+
type: effectiveType,
|
|
242
|
+
valueClass: item.analysis.valueClass
|
|
243
|
+
},
|
|
244
|
+
effectiveType,
|
|
245
|
+
is_type_mismatch: false,
|
|
246
|
+
schema: 0,
|
|
247
|
+
cst_class: 'derived',
|
|
248
|
+
status: item.analysis.success ? 'verified' : 'incorrect',
|
|
249
|
+
is_template: false,
|
|
250
|
+
is_simple_expression: true,
|
|
251
|
+
parent_schema_index: 0,
|
|
252
|
+
parent_schema: null,
|
|
253
|
+
is_inherited: false,
|
|
254
|
+
has_inherited_children: false,
|
|
255
|
+
spawn: [],
|
|
256
|
+
spawn_alias: []
|
|
257
|
+
} as unknown as Constituenta;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function toPublicEvaluationResult(
|
|
261
|
+
value: Value | null,
|
|
262
|
+
errors: { code: number; from: number; to: number; params?: readonly string[] }[],
|
|
263
|
+
iterations: number,
|
|
264
|
+
cacheHits: number,
|
|
265
|
+
status: EvalStatus
|
|
266
|
+
): EvaluationResult {
|
|
267
|
+
const diagnostics = errors.map(toPublicError);
|
|
268
|
+
return {
|
|
269
|
+
success: diagnostics.length === 0 && value !== null,
|
|
270
|
+
value: value as EvaluationResult['value'],
|
|
271
|
+
status,
|
|
272
|
+
iterations,
|
|
273
|
+
cacheHits,
|
|
274
|
+
diagnostics
|
|
275
|
+
};
|
|
276
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { RSLangAnalyzer, type AnalysisFull, type ValueClass } from '@rsconcept/domain/rslang';
|
|
2
|
+
import { getAnalysisFor } from '@rsconcept/domain/library/rsform-api';
|
|
3
|
+
import { CstType, type RSForm } from '@rsconcept/domain/library/rsform';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
type AnalysisResult,
|
|
7
|
+
type ConstituentaDraft,
|
|
8
|
+
type ConstituentaState,
|
|
9
|
+
type DiagnosticRecord,
|
|
10
|
+
type SessionState
|
|
11
|
+
} from '../models';
|
|
12
|
+
import { toPublicAnalysis, toPublicError } from './types';
|
|
13
|
+
|
|
14
|
+
export class SchemaAdapter {
|
|
15
|
+
public analyzeAgainstSession(
|
|
16
|
+
session: SessionState,
|
|
17
|
+
draft: ConstituentaDraft
|
|
18
|
+
): { result: AnalysisResult; diagnostics: DiagnosticRecord[] } {
|
|
19
|
+
const analyzer = this.buildAnalyzer(session);
|
|
20
|
+
const schema = this.toPseudoRSFormState(session, analyzer);
|
|
21
|
+
const analysis = getAnalysisFor(draft.definitionFormal, draft.cstType, schema as unknown as RSForm, draft.alias);
|
|
22
|
+
const result = toPublicAnalysis({
|
|
23
|
+
success: analysis.success,
|
|
24
|
+
type: analysis.type as Record<string, unknown> | null,
|
|
25
|
+
valueClass: analysis.valueClass,
|
|
26
|
+
errors: analysis.errors
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
result,
|
|
30
|
+
diagnostics: analysis.errors.map(error => ({
|
|
31
|
+
sessionId: session.sessionId,
|
|
32
|
+
constituentId: draft.id,
|
|
33
|
+
expression: draft.definitionFormal,
|
|
34
|
+
error: toPublicError(error)
|
|
35
|
+
}))
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public mergeStateWithDraft(
|
|
40
|
+
session: SessionState,
|
|
41
|
+
draft: ConstituentaDraft,
|
|
42
|
+
analysis: AnalysisResult
|
|
43
|
+
): ConstituentaState {
|
|
44
|
+
const state: ConstituentaState = {
|
|
45
|
+
...draft,
|
|
46
|
+
term: draft.term ?? '',
|
|
47
|
+
definitionText: draft.definitionText ?? '',
|
|
48
|
+
convention: draft.convention ?? '',
|
|
49
|
+
analysis
|
|
50
|
+
};
|
|
51
|
+
const index = session.items.findIndex(item => item.id === draft.id);
|
|
52
|
+
if (index === -1) {
|
|
53
|
+
session.items.push(state);
|
|
54
|
+
} else {
|
|
55
|
+
session.items[index] = state;
|
|
56
|
+
}
|
|
57
|
+
session.updatedAt = new Date().toISOString();
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public toPseudoRSFormState(
|
|
62
|
+
session: SessionState,
|
|
63
|
+
analyzer: RSLangAnalyzer
|
|
64
|
+
): Pick<RSForm, 'items' | 'cstByAlias' | 'analyzer'> {
|
|
65
|
+
const cstByAlias = new Map(session.items.map(item => [item.alias, item]));
|
|
66
|
+
return {
|
|
67
|
+
items: session.items as unknown as RSForm['items'],
|
|
68
|
+
cstByAlias: cstByAlias as unknown as RSForm['cstByAlias'],
|
|
69
|
+
analyzer
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private buildAnalyzer(session: SessionState): RSLangAnalyzer {
|
|
74
|
+
const analyzer = new RSLangAnalyzer();
|
|
75
|
+
for (const item of session.items) {
|
|
76
|
+
if (item.cstType === CstType.BASE) {
|
|
77
|
+
analyzer.addBase(item.alias);
|
|
78
|
+
}
|
|
79
|
+
analyzer.setGlobal(
|
|
80
|
+
item.alias,
|
|
81
|
+
item.analysis.type as AnalysisFull['type'],
|
|
82
|
+
item.analysis.valueClass as ValueClass | null
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
return analyzer;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ValueClass } from '@rsconcept/domain/rslang';
|
|
2
|
+
|
|
3
|
+
import { type AnalysisResult, type RSToolErrorDescription } from '../models';
|
|
4
|
+
|
|
5
|
+
export interface DomainErrorLike {
|
|
6
|
+
code: number;
|
|
7
|
+
from: number;
|
|
8
|
+
to: number;
|
|
9
|
+
params?: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DomainAnalysisLike {
|
|
13
|
+
success: boolean;
|
|
14
|
+
type: Record<string, unknown> | null;
|
|
15
|
+
valueClass: ValueClass | null;
|
|
16
|
+
errors: DomainErrorLike[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function toPublicError(error: DomainErrorLike): RSToolErrorDescription {
|
|
20
|
+
return {
|
|
21
|
+
code: error.code,
|
|
22
|
+
from: error.from,
|
|
23
|
+
to: error.to,
|
|
24
|
+
params: error.params
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function toPublicAnalysis(analysis: DomainAnalysisLike): AnalysisResult {
|
|
29
|
+
return {
|
|
30
|
+
success: analysis.success,
|
|
31
|
+
type: analysis.type,
|
|
32
|
+
valueClass: analysis.valueClass,
|
|
33
|
+
diagnostics: analysis.errors.map(toPublicError)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type CstType, type RSToolErrorDescription, type ValueClass } from './common';
|
|
2
|
+
|
|
3
|
+
export interface AnalyzeExpressionInput {
|
|
4
|
+
expression: string;
|
|
5
|
+
cstType: CstType;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface AnalysisResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
type: Record<string, unknown> | null;
|
|
11
|
+
valueClass: ValueClass | null;
|
|
12
|
+
diagnostics: RSToolErrorDescription[];
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CstType } from '@rsconcept/domain/library/rsform';
|
|
2
|
+
import { EvalStatus, type BasicBinding } from '@rsconcept/domain/library/rsmodel';
|
|
3
|
+
import { ValueClass } from '@rsconcept/domain/rslang';
|
|
4
|
+
import { RSErrorCode } from '@rsconcept/domain/rslang/error';
|
|
5
|
+
|
|
6
|
+
export { CstType, EvalStatus, RSErrorCode, ValueClass };
|
|
7
|
+
export type { BasicBinding };
|
|
8
|
+
|
|
9
|
+
/** Runtime evaluation value: number, nested array (set/tuple), or boolean 0/1. */
|
|
10
|
+
export type RSToolValue = number | RSToolValue[];
|
|
11
|
+
|
|
12
|
+
export interface RSToolErrorDescription {
|
|
13
|
+
code: number;
|
|
14
|
+
from: number;
|
|
15
|
+
to: number;
|
|
16
|
+
params?: readonly string[];
|
|
17
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type AnalysisResult } from './analysis';
|
|
2
|
+
import { type CstType } from './common';
|
|
3
|
+
import { type DiagnosticRecord } from './diagnostic';
|
|
4
|
+
|
|
5
|
+
export interface ConstituentaDraft {
|
|
6
|
+
id: number;
|
|
7
|
+
/** Alias */
|
|
8
|
+
alias: string;
|
|
9
|
+
/** CST type */
|
|
10
|
+
cstType: CstType;
|
|
11
|
+
/** Formal definition */
|
|
12
|
+
definitionFormal: string;
|
|
13
|
+
/** Natural-language term */
|
|
14
|
+
term?: string;
|
|
15
|
+
/** Natural-language definition */
|
|
16
|
+
definitionText?: string;
|
|
17
|
+
/** Convention or comment */
|
|
18
|
+
convention?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ConstituentaState extends Omit<ConstituentaDraft, 'term' | 'definitionText' | 'convention'> {
|
|
22
|
+
term: string;
|
|
23
|
+
definitionText: string;
|
|
24
|
+
convention: string;
|
|
25
|
+
analysis: AnalysisResult;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AddOrUpdateConstituentaInput {
|
|
29
|
+
draft: ConstituentaDraft;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AddOrUpdateConstituentaResult {
|
|
33
|
+
state: ConstituentaState;
|
|
34
|
+
diagnostics: DiagnosticRecord[];
|
|
35
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RSToolErrorDescription } from './common';
|
|
2
|
+
|
|
3
|
+
export interface DiagnosticRecord {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
constituentId?: number;
|
|
6
|
+
expression: string;
|
|
7
|
+
error: RSToolErrorDescription;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ListDiagnosticsFilters {
|
|
11
|
+
constituentId?: number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BasicBinding,
|
|
3
|
+
type CstType,
|
|
4
|
+
type EvalStatus,
|
|
5
|
+
type RSToolErrorDescription,
|
|
6
|
+
type RSToolValue
|
|
7
|
+
} from './common';
|
|
8
|
+
|
|
9
|
+
export interface EvaluateExpressionInput {
|
|
10
|
+
expression: string;
|
|
11
|
+
cstType: CstType;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface EvaluateConstituentaInput {
|
|
15
|
+
constituentId: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface EvaluationResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
value: RSToolValue | BasicBinding | null;
|
|
21
|
+
status: EvalStatus;
|
|
22
|
+
iterations: number;
|
|
23
|
+
cacheHits: number;
|
|
24
|
+
diagnostics: RSToolErrorDescription[];
|
|
25
|
+
}
|