@rsconcept/rstool 0.10.2 → 1.0.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 +41 -31
- package/dist/agent-workflow-D-PSIb-m.d.ts +70 -0
- package/dist/analysis-LLnPhmGa.d.ts +23 -0
- package/dist/{common-DxLg3eXX.d.ts → common-DHJalS-Q.d.ts} +6 -1
- package/dist/constituenta-DnGR6bnM.d.ts +54 -0
- package/dist/diagnostic-D9yl_mEL.d.ts +19 -0
- package/dist/evaluation-Cns8BFm4.d.ts +31 -0
- package/dist/index.d.ts +11 -11
- package/dist/index.js +1 -1
- package/dist/mappers/model-adapter.d.ts +3 -3
- package/dist/mappers/schema-adapter.d.ts +4 -4
- package/dist/mappers/types.d.ts +6 -2
- package/dist/mappers/types.js +2 -0
- package/dist/mappers/types.js.map +1 -1
- package/dist/{model-value-SFAVj0dw.d.ts → model-value-BbonPzMz.d.ts} +14 -3
- package/dist/models/agent-workflow.d.ts +2 -0
- package/dist/models/agent-workflow.js +1 -0
- package/dist/models/analysis.d.ts +1 -1
- package/dist/models/common.d.ts +1 -1
- package/dist/models/constituenta.d.ts +2 -2
- package/dist/models/diagnostic.d.ts +1 -1
- package/dist/models/evaluation.d.ts +2 -2
- package/dist/models/index.d.ts +11 -11
- package/dist/models/index.js +2 -2
- package/dist/models/model-value.d.ts +2 -2
- package/dist/models/rstool-agent.d.ts +1 -1
- package/dist/models/rstool-agent.js +1 -1
- package/dist/models/session.d.ts +1 -1
- package/dist/models/tool-contract.d.ts +2 -2
- package/dist/models/tool-contract.js +2 -1
- package/dist/models/tool-contract.js.map +1 -1
- package/dist/rstool-agent-_8bplZnb.d.ts +71 -0
- package/dist/rstool-agent-kijHA9ML.js +476 -0
- package/dist/rstool-agent-kijHA9ML.js.map +1 -0
- package/dist/session/session-store.d.ts +18 -5
- package/dist/session/session-store.js +1 -64
- package/dist/{session-BPgsE80c.d.ts → session-ChexW8i7.d.ts} +11 -8
- package/dist/session-store-C3jyOSqI.js +142 -0
- package/dist/session-store-C3jyOSqI.js.map +1 -0
- package/dist/tool-contract-5_Q44DGE.d.ts +164 -0
- package/dist/wrapper/client.d.ts +23 -0
- package/dist/wrapper/client.js +17 -0
- package/dist/wrapper/client.js.map +1 -1
- package/dist/wrapper/stdio-wrapper.js +62 -52
- package/dist/wrapper/stdio-wrapper.js.map +1 -1
- package/docs/CONSTITUENTA.md +2 -2
- package/docs/DIAGNOSTICS.md +20 -18
- package/docs/MODEL-TESTING.md +3 -3
- package/docs/PORTAL-API.md +24 -18
- package/examples/README.md +1 -1
- package/examples/agent-client.ts +11 -41
- package/examples/build-chocolate-nim-rsform.ts +23 -18
- package/examples/chocolate-nim/build-rsform.ts +23 -18
- package/examples/chocolate-nim/build-rsmodel.ts +10 -12
- package/examples/chocolate-nim/rsform-session.json +290 -290
- package/examples/chocolate-nim/rsmodel-session.json +291 -291
- package/examples/expression-bank/bank-constituents.ts +304 -53
- package/examples/expression-bank/build-rsform.ts +19 -16
- package/examples/expression-bank/rsform-session.json +1551 -1551
- package/examples/kinship/build-rsform.ts +23 -18
- package/examples/kinship/build-rsmodel.ts +13 -15
- package/examples/kinship/rsform-session.json +219 -219
- package/examples/kinship/rsmodel-session.json +221 -221
- package/examples/kinship/session.ts +19 -21
- package/examples/movd/build-rsform.ts +23 -18
- package/examples/movd/build-rsmodel.ts +18 -20
- package/examples/movd/rsform-session.json +262 -262
- package/examples/movd/rsmodel-session.json +264 -264
- package/examples/sample/build-rsform.ts +19 -50
- package/examples/sample/build-rsmodel.ts +25 -44
- package/examples/sample/rsform-session.json +36 -33
- package/examples/sample/rsmodel-session.json +36 -33
- package/examples/template-apply/build-rsform.ts +27 -24
- package/examples/template-apply/rsform-session.json +48 -48
- package/package.json +3 -3
- package/skills/rstool-helper/EXAMPLES.md +44 -116
- package/skills/rstool-helper/GUIDE.md +40 -25
- package/skills/rstool-helper/REFERENCE.md +40 -177
- package/src/index.ts +24 -17
- package/src/mappers/portal-adapter.ts +43 -0
- package/src/mappers/types.ts +4 -0
- package/src/models/agent-workflow.ts +78 -0
- package/src/models/analysis.ts +7 -0
- package/src/models/common.ts +7 -0
- package/src/models/constituenta.ts +24 -6
- package/src/models/diagnostic.ts +4 -0
- package/src/models/evaluation.ts +11 -0
- package/src/models/import-detect.ts +39 -0
- package/src/models/import-export.ts +24 -0
- package/src/models/index.ts +22 -14
- package/src/models/model-value.ts +12 -0
- package/src/models/portal-json.ts +44 -0
- package/src/models/rstool-agent.test.ts +300 -147
- package/src/models/rstool-agent.ts +350 -93
- package/src/models/session.ts +8 -5
- package/src/models/tool-contract.ts +81 -42
- package/src/session/batch-apply.test.ts +28 -0
- package/src/session/batch-apply.ts +47 -0
- package/src/session/persistence.ts +56 -0
- package/src/session/session-store.ts +67 -4
- package/src/wrapper/client.ts +23 -0
- package/src/wrapper/stdio-wrapper.ts +59 -49
- package/dist/analysis-JiwOYDKx.d.ts +0 -16
- package/dist/constituenta-Dnd6iToB.d.ts +0 -36
- package/dist/diagnostic-BMYvciz8.d.ts +0 -15
- package/dist/evaluation-CCVYH0wA.d.ts +0 -21
- package/dist/index-uhkmwruf.d.ts +0 -46
- package/dist/rstool-agent-BZi5jO1y.js +0 -158
- package/dist/rstool-agent-BZi5jO1y.js.map +0 -1
- package/dist/rstool-agent-pRaPnZay.d.ts +0 -35
- package/dist/session/session-store.js.map +0 -1
- package/dist/tool-contract-n1ghUOrK.d.ts +0 -32
|
@@ -1,31 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
portalDetailsToDrafts,
|
|
3
|
+
portalDetailsToSessionSeed,
|
|
4
|
+
portalSchemaToDrafts,
|
|
5
|
+
portalSchemaToSessionSeed
|
|
6
|
+
} from '../mappers/portal-adapter';
|
|
1
7
|
import { ModelAdapter } from '../mappers/model-adapter';
|
|
2
8
|
import { SchemaAdapter } from '../mappers/schema-adapter';
|
|
9
|
+
import { orderDrafts } from '../session/batch-apply';
|
|
3
10
|
import { SessionStore } from '../session/session-store';
|
|
11
|
+
import {
|
|
12
|
+
type AgentConstituentaPatch,
|
|
13
|
+
type ApplySchemaPatchInput,
|
|
14
|
+
type ApplySchemaPatchResult,
|
|
15
|
+
type SessionStateDetail,
|
|
16
|
+
type SessionStateResult,
|
|
17
|
+
type SessionSummary
|
|
18
|
+
} from './agent-workflow';
|
|
4
19
|
import { type AnalysisResult, type AnalyzeExpressionInput } from './analysis';
|
|
20
|
+
import { CstType } from './common';
|
|
5
21
|
import {
|
|
6
22
|
type AddOrUpdateConstituentaInput,
|
|
7
|
-
type AddOrUpdateConstituentaResult
|
|
23
|
+
type AddOrUpdateConstituentaResult,
|
|
24
|
+
type ApplyConstituentsInput,
|
|
25
|
+
type ApplyConstituentsResult,
|
|
26
|
+
type ConstituentaDraft,
|
|
27
|
+
type ConstituentaState
|
|
8
28
|
} from './constituenta';
|
|
9
|
-
import { type ListDiagnosticsFilters } from './diagnostic';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from './evaluation';
|
|
15
|
-
import {
|
|
16
|
-
type ClearConstituentaValuesInput,
|
|
17
|
-
type RecalculateModelResult,
|
|
18
|
-
type SessionModelState,
|
|
19
|
-
type SetConstituentaValueInput,
|
|
20
|
-
type SetConstituentaValuesInput
|
|
21
|
-
} from './model-value';
|
|
29
|
+
import { type DiagnosticRecord, type ListDiagnosticsFilters } from './diagnostic';
|
|
30
|
+
import { type EvaluateInput, type EvaluationResult } from './evaluation';
|
|
31
|
+
import { detectImportKind, parseImportPayload } from './import-detect';
|
|
32
|
+
import { type ExportPortalInput, type ExportPortalResult, type ImportDataKind } from './import-export';
|
|
33
|
+
import { type RecalculateModelResult, type SessionModelState, type SetModelValuesInput } from './model-value';
|
|
22
34
|
import {
|
|
23
35
|
PORTAL_JSON_CONTRACT_VERSION,
|
|
24
36
|
type PortalModelImportData,
|
|
37
|
+
type PortalRsformDetails,
|
|
25
38
|
type PortalSchemaImportData
|
|
26
39
|
} from './portal-json';
|
|
27
40
|
import { type SessionHandle, type SessionRevision, type SessionState } from './session';
|
|
28
|
-
import { CONTRACT_VERSION, type RSToolAgentContract } from './tool-contract';
|
|
41
|
+
import { CONTRACT_VERSION, type RSToolAgentContract, type RSToolAgentOptions } from './tool-contract';
|
|
29
42
|
|
|
30
43
|
function normalizeImportedState(state: SessionState): SessionState {
|
|
31
44
|
return {
|
|
@@ -42,9 +55,7 @@ function portalImportMetadata(
|
|
|
42
55
|
kind: 'schema' | 'model'
|
|
43
56
|
): Pick<PortalSchemaImportData, 'title' | 'alias' | 'description'> {
|
|
44
57
|
const defaults =
|
|
45
|
-
kind === 'schema'
|
|
46
|
-
? { title: 'Conceptual schema', alias: 'SCHEMA' }
|
|
47
|
-
: { title: 'Conceptual model', alias: 'MODEL' };
|
|
58
|
+
kind === 'schema' ? { title: 'Conceptual schema', alias: 'SCHEMA' } : { title: 'Conceptual model', alias: 'MODEL' };
|
|
48
59
|
const title = session.title.trim();
|
|
49
60
|
const alias = session.alias.trim();
|
|
50
61
|
return {
|
|
@@ -54,60 +65,143 @@ function portalImportMetadata(
|
|
|
54
65
|
};
|
|
55
66
|
}
|
|
56
67
|
|
|
68
|
+
function inferCstType(alias: string): CstType {
|
|
69
|
+
const prefix = alias.trim().charAt(0).toUpperCase();
|
|
70
|
+
switch (prefix) {
|
|
71
|
+
case 'X':
|
|
72
|
+
return CstType.BASE;
|
|
73
|
+
case 'C':
|
|
74
|
+
return CstType.CONSTANT;
|
|
75
|
+
case 'S':
|
|
76
|
+
return CstType.STRUCTURED;
|
|
77
|
+
case 'D':
|
|
78
|
+
return CstType.TERM;
|
|
79
|
+
case 'A':
|
|
80
|
+
return CstType.AXIOM;
|
|
81
|
+
case 'F':
|
|
82
|
+
return CstType.FUNCTION;
|
|
83
|
+
case 'P':
|
|
84
|
+
return CstType.PREDICATE;
|
|
85
|
+
default:
|
|
86
|
+
throw new Error(`Cannot infer cstType from alias "${alias}"; pass cstType explicitly`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Agent-facing entry point for incremental RSForm editing, analysis, diagnostics,
|
|
92
|
+
* modeling, and evaluation.
|
|
93
|
+
*
|
|
94
|
+
* Holds in-memory (optionally persisted) sessions and delegates language work
|
|
95
|
+
* to internal schema and model adapters.
|
|
96
|
+
*/
|
|
57
97
|
export class RSToolAgent implements RSToolAgentContract {
|
|
58
98
|
public readonly contractVersion = CONTRACT_VERSION;
|
|
59
|
-
private readonly sessions
|
|
99
|
+
private readonly sessions: SessionStore;
|
|
60
100
|
private readonly adapter = new SchemaAdapter();
|
|
61
101
|
private readonly evaluation = new ModelAdapter();
|
|
102
|
+
private currentSessionId: string | null;
|
|
103
|
+
|
|
104
|
+
/** @param options - Optional persistence directory for session storage. */
|
|
105
|
+
public constructor(options: RSToolAgentOptions = {}) {
|
|
106
|
+
this.sessions = new SessionStore({ persistenceDir: options.persistenceDir });
|
|
107
|
+
this.currentSessionId = this.sessions.loadCurrentSessionId();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** @inheritdoc */
|
|
111
|
+
public ensureSession(initial?: Partial<SessionState>): SessionHandle {
|
|
112
|
+
const current = this.getCurrentSession();
|
|
113
|
+
return current ?? this.createSession(initial);
|
|
114
|
+
}
|
|
62
115
|
|
|
116
|
+
/** @inheritdoc */
|
|
63
117
|
public createSession(initial?: Partial<SessionState>): SessionHandle {
|
|
64
|
-
return this.sessions.create(initial, this.contractVersion);
|
|
118
|
+
return this.trackSession(this.sessions.create(initial, this.contractVersion));
|
|
65
119
|
}
|
|
66
120
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
121
|
+
/** @inheritdoc */
|
|
122
|
+
public getCurrentSession(): SessionHandle | null {
|
|
123
|
+
if (!this.currentSessionId) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
if (!this.sessions.has(this.currentSessionId)) {
|
|
127
|
+
this.currentSessionId = null;
|
|
128
|
+
this.sessions.saveCurrentSessionId(null);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return { sessionId: this.currentSessionId, contractVersion: this.contractVersion };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** @inheritdoc */
|
|
135
|
+
public setCurrentSession(sessionId: string): SessionHandle {
|
|
136
|
+
if (!this.sessions.has(sessionId)) {
|
|
137
|
+
throw new Error(`Unknown session: ${sessionId}`);
|
|
138
|
+
}
|
|
139
|
+
return this.trackSession({ sessionId, contractVersion: this.contractVersion });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** @inheritdoc */
|
|
143
|
+
public applySchemaPatch(input: ApplySchemaPatchInput, sessionId?: string): ApplySchemaPatchResult {
|
|
144
|
+
const session = sessionId ? this.setCurrentSession(sessionId) : this.ensureSession(input.initial);
|
|
145
|
+
const drafts = this.resolveAgentPatches(session.sessionId, input.items);
|
|
146
|
+
const result = this.applyConstituents(
|
|
147
|
+
{
|
|
148
|
+
drafts,
|
|
149
|
+
mode: input.mode
|
|
150
|
+
},
|
|
151
|
+
session.sessionId
|
|
152
|
+
);
|
|
153
|
+
const revision =
|
|
154
|
+
result.success && input.commitMessage ? this.commitStep(input.commitMessage, session.sessionId) : undefined;
|
|
75
155
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
156
|
+
...result,
|
|
157
|
+
session,
|
|
158
|
+
summary: this.buildSessionSummary(session.sessionId),
|
|
159
|
+
revision
|
|
78
160
|
};
|
|
79
161
|
}
|
|
80
162
|
|
|
81
|
-
|
|
82
|
-
|
|
163
|
+
/** @inheritdoc */
|
|
164
|
+
public getSessionState(detail: SessionStateDetail = 'summary', sessionId?: string): SessionStateResult {
|
|
165
|
+
if (detail === 'full') {
|
|
166
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
167
|
+
return structuredClone(envelope.state);
|
|
168
|
+
}
|
|
169
|
+
return this.buildSessionSummary(sessionId);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** @inheritdoc */
|
|
173
|
+
public listDiagnostics(filters?: ListDiagnosticsFilters, sessionId?: string) {
|
|
174
|
+
return this.sessions.listDiagnostics(this.resolveSessionId(sessionId), filters);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** @inheritdoc */
|
|
178
|
+
public analyzeExpression(input: AnalyzeExpressionInput, sessionId?: string): AnalysisResult {
|
|
179
|
+
const id = this.resolveSessionId(sessionId);
|
|
180
|
+
const envelope = this.sessions.get(id);
|
|
83
181
|
const { result, diagnostics } = this.adapter.analyzeAgainstSession(envelope.state, {
|
|
84
182
|
id: -1,
|
|
85
183
|
alias: '_analysis',
|
|
86
184
|
cstType: input.cstType,
|
|
87
185
|
definitionFormal: input.expression
|
|
88
186
|
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
187
|
+
if (input.recordDiagnostics) {
|
|
188
|
+
this.sessions.replaceDiagnosticsForConstituent(
|
|
189
|
+
id,
|
|
190
|
+
undefined,
|
|
191
|
+
diagnostics.map(item => ({ ...item, constituentId: undefined }))
|
|
192
|
+
);
|
|
193
|
+
}
|
|
93
194
|
return result;
|
|
94
195
|
}
|
|
95
196
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public listDiagnostics(sessionId: string, filters?: ListDiagnosticsFilters) {
|
|
102
|
-
return this.sessions.listDiagnostics(sessionId, filters);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
public commitStep(sessionId: string, message?: string): SessionRevision {
|
|
106
|
-
return this.sessions.addRevision(sessionId, message);
|
|
197
|
+
/** @inheritdoc */
|
|
198
|
+
public commitStep(message?: string, sessionId?: string): SessionRevision {
|
|
199
|
+
return this.sessions.addRevision(this.resolveSessionId(sessionId), message);
|
|
107
200
|
}
|
|
108
201
|
|
|
109
|
-
|
|
110
|
-
|
|
202
|
+
/** @inheritdoc */
|
|
203
|
+
public exportSession(sessionId?: string): string {
|
|
204
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
111
205
|
return JSON.stringify(
|
|
112
206
|
{
|
|
113
207
|
contractVersion: this.contractVersion,
|
|
@@ -119,9 +213,153 @@ export class RSToolAgent implements RSToolAgentContract {
|
|
|
119
213
|
);
|
|
120
214
|
}
|
|
121
215
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
216
|
+
/** @inheritdoc */
|
|
217
|
+
public exportPortal(input: ExportPortalInput, sessionId?: string): ExportPortalResult {
|
|
218
|
+
const format = input.format ?? 'json';
|
|
219
|
+
const object =
|
|
220
|
+
input.kind === 'schema' ? this.buildPortalSchemaObject(sessionId) : this.buildPortalModelObject(sessionId);
|
|
221
|
+
return format === 'object' ? object : JSON.stringify(object, null, 2);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** @inheritdoc */
|
|
225
|
+
public importData(payload: string | object, kind: ImportDataKind = 'auto'): SessionHandle {
|
|
226
|
+
const parsed = parseImportPayload(payload);
|
|
227
|
+
const resolvedKind = kind === 'auto' ? detectImportKind(parsed) : kind;
|
|
228
|
+
|
|
229
|
+
switch (resolvedKind) {
|
|
230
|
+
case 'session':
|
|
231
|
+
return this.importSessionExport(parsed);
|
|
232
|
+
case 'portal-schema':
|
|
233
|
+
return this.importPortalSchemaData(parsed as PortalSchemaImportData);
|
|
234
|
+
case 'portal-details':
|
|
235
|
+
return this.importPortalDetailsData(parsed as PortalRsformDetails);
|
|
236
|
+
default:
|
|
237
|
+
throw new Error(`Unsupported import kind: ${resolvedKind as string}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** @inheritdoc */
|
|
242
|
+
public async setModelValues(input: SetModelValuesInput, sessionId?: string): Promise<SessionModelState> {
|
|
243
|
+
const id = this.resolveSessionId(sessionId);
|
|
244
|
+
let state = this.sessions.get(id).state;
|
|
245
|
+
|
|
246
|
+
if (input.clear?.length) {
|
|
247
|
+
const model = await this.evaluation.clearConstituentaValues(state, input.clear);
|
|
248
|
+
state = { ...state, model };
|
|
249
|
+
this.sessions.replaceState(id, state);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (input.set?.length) {
|
|
253
|
+
state = this.sessions.get(id).state;
|
|
254
|
+
const model = await this.evaluation.setConstituentaValues(state, { items: input.set });
|
|
255
|
+
state = { ...state, model };
|
|
256
|
+
this.sessions.replaceState(id, state);
|
|
257
|
+
return model;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return structuredClone(this.sessions.get(id).state.model);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** @inheritdoc */
|
|
264
|
+
public getModelState(sessionId?: string): SessionModelState {
|
|
265
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
266
|
+
return structuredClone(envelope.state.model);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** @inheritdoc */
|
|
270
|
+
public evaluate(input: EvaluateInput, sessionId?: string): EvaluationResult {
|
|
271
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
272
|
+
|
|
273
|
+
if (input.constituentId !== undefined) {
|
|
274
|
+
return this.evaluation.evaluateConstituenta(envelope.state, input.constituentId);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (input.expression !== undefined && input.cstType !== undefined) {
|
|
278
|
+
return this.evaluation.evaluateExpression(envelope.state, input.expression, input.cstType);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
throw new Error('evaluate requires constituentId or expression with cstType');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** @inheritdoc */
|
|
285
|
+
public recalculateModel(sessionId?: string): RecalculateModelResult {
|
|
286
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
287
|
+
return this.evaluation.recalculateModel(envelope.state);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private addOrUpdateConstituenta(
|
|
291
|
+
input: AddOrUpdateConstituentaInput,
|
|
292
|
+
sessionId?: string
|
|
293
|
+
): AddOrUpdateConstituentaResult {
|
|
294
|
+
const id = this.resolveSessionId(sessionId);
|
|
295
|
+
const envelope = this.sessions.get(id);
|
|
296
|
+
const { result, diagnostics } = this.adapter.analyzeAgainstSession(envelope.state, input.draft);
|
|
297
|
+
const state = this.adapter.mergeStateWithDraft(envelope.state, input.draft, result);
|
|
298
|
+
this.sessions.replaceDiagnosticsForConstituent(id, input.draft.id, diagnostics);
|
|
299
|
+
return { state, diagnostics };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private applyConstituents(input: ApplyConstituentsInput, sessionId?: string): ApplyConstituentsResult {
|
|
303
|
+
const id = this.resolveSessionId(sessionId);
|
|
304
|
+
const mode = input.mode ?? 'atomic';
|
|
305
|
+
const ordered = orderDrafts(this.sessions.get(id).state.items, input.drafts);
|
|
306
|
+
const snapshot = this.sessions.snapshot(id);
|
|
307
|
+
const applied: ConstituentaState[] = [];
|
|
308
|
+
const failed: ApplyConstituentsResult['failed'] = [];
|
|
309
|
+
|
|
310
|
+
for (const draft of ordered) {
|
|
311
|
+
const result = this.addOrUpdateConstituenta({ draft }, id);
|
|
312
|
+
if (result.state.analysis.success) {
|
|
313
|
+
applied.push(result.state);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
failed.push({ draft, diagnostics: result.diagnostics });
|
|
317
|
+
if (mode === 'atomic') {
|
|
318
|
+
this.sessions.restore(id, snapshot);
|
|
319
|
+
return {
|
|
320
|
+
success: false,
|
|
321
|
+
applied: [],
|
|
322
|
+
failed,
|
|
323
|
+
diagnostics: this.sessions.listDiagnostics(id)
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
success: failed.length === 0,
|
|
330
|
+
applied,
|
|
331
|
+
failed,
|
|
332
|
+
diagnostics: this.sessions.listDiagnostics(id)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private buildSessionSummary(sessionId?: string): SessionSummary {
|
|
337
|
+
const id = this.resolveSessionId(sessionId);
|
|
338
|
+
const envelope = this.sessions.get(id);
|
|
339
|
+
const diagnostics = this.sessions.listDiagnostics(id);
|
|
340
|
+
return {
|
|
341
|
+
sessionId: id,
|
|
342
|
+
contractVersion: this.contractVersion,
|
|
343
|
+
alias: envelope.state.alias,
|
|
344
|
+
title: envelope.state.title,
|
|
345
|
+
comment: envelope.state.comment,
|
|
346
|
+
itemCount: envelope.state.items.length,
|
|
347
|
+
modelItemCount: envelope.state.model.items.length,
|
|
348
|
+
diagnosticsCount: diagnostics.length,
|
|
349
|
+
items: envelope.state.items.map(item => ({
|
|
350
|
+
id: item.id,
|
|
351
|
+
alias: item.alias,
|
|
352
|
+
cstType: item.cstType,
|
|
353
|
+
analysisSuccess: item.analysis.success
|
|
354
|
+
})),
|
|
355
|
+
diagnostics,
|
|
356
|
+
lastRevision: envelope.state.revisions.at(-1)
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private buildPortalSchemaObject(sessionId?: string): PortalSchemaImportData {
|
|
361
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
362
|
+
return {
|
|
125
363
|
contract_version: PORTAL_JSON_CONTRACT_VERSION,
|
|
126
364
|
...portalImportMetadata(envelope.state, 'schema'),
|
|
127
365
|
items: envelope.state.items.map(item => ({
|
|
@@ -141,12 +379,11 @@ export class RSToolAgent implements RSToolAgentContract {
|
|
|
141
379
|
})),
|
|
142
380
|
attribution: []
|
|
143
381
|
};
|
|
144
|
-
return JSON.stringify(payload, null, 2);
|
|
145
382
|
}
|
|
146
383
|
|
|
147
|
-
|
|
148
|
-
const envelope = this.sessions.get(sessionId);
|
|
149
|
-
|
|
384
|
+
private buildPortalModelObject(sessionId?: string): PortalModelImportData {
|
|
385
|
+
const envelope = this.sessions.get(this.resolveSessionId(sessionId));
|
|
386
|
+
return {
|
|
150
387
|
contract_version: PORTAL_JSON_CONTRACT_VERSION,
|
|
151
388
|
...portalImportMetadata(envelope.state, 'model'),
|
|
152
389
|
items: envelope.state.model.items.map(item => ({
|
|
@@ -155,57 +392,77 @@ export class RSToolAgent implements RSToolAgentContract {
|
|
|
155
392
|
value: item.value
|
|
156
393
|
}))
|
|
157
394
|
};
|
|
158
|
-
return JSON.stringify(payload, null, 2);
|
|
159
395
|
}
|
|
160
396
|
|
|
161
|
-
|
|
162
|
-
|
|
397
|
+
private importSessionExport(parsed: unknown): SessionHandle {
|
|
398
|
+
if (!parsed || typeof parsed !== 'object' || !('state' in parsed)) {
|
|
399
|
+
throw new Error('Invalid session export payload');
|
|
400
|
+
}
|
|
401
|
+
const data = parsed as {
|
|
163
402
|
state: SessionState;
|
|
403
|
+
diagnostics?: DiagnosticRecord[];
|
|
164
404
|
};
|
|
165
|
-
|
|
405
|
+
const handle = this.sessions.create(normalizeImportedState(data.state), this.contractVersion);
|
|
406
|
+
if (data.diagnostics?.length) {
|
|
407
|
+
this.sessions.setDiagnostics(handle.sessionId, data.diagnostics);
|
|
408
|
+
}
|
|
409
|
+
return this.trackSession(handle);
|
|
166
410
|
}
|
|
167
411
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const envelope = this.sessions.get(sessionId);
|
|
173
|
-
return this.evaluation.setConstituentaValue(envelope.state, input);
|
|
412
|
+
private importPortalSchemaData(data: PortalSchemaImportData): SessionHandle {
|
|
413
|
+
const handle = this.createSession(portalSchemaToSessionSeed(data));
|
|
414
|
+
this.applyConstituents({ drafts: portalSchemaToDrafts(data), mode: 'best_effort' }, handle.sessionId);
|
|
415
|
+
return handle;
|
|
174
416
|
}
|
|
175
417
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const envelope = this.sessions.get(sessionId);
|
|
181
|
-
return this.evaluation.setConstituentaValues(envelope.state, input);
|
|
418
|
+
private importPortalDetailsData(data: PortalRsformDetails): SessionHandle {
|
|
419
|
+
const handle = this.createSession(portalDetailsToSessionSeed(data));
|
|
420
|
+
this.applyConstituents({ drafts: portalDetailsToDrafts(data), mode: 'best_effort' }, handle.sessionId);
|
|
421
|
+
return handle;
|
|
182
422
|
}
|
|
183
423
|
|
|
184
|
-
|
|
185
|
-
sessionId
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const envelope = this.sessions.get(sessionId);
|
|
189
|
-
return this.evaluation.clearConstituentaValues(envelope.state, input.items);
|
|
190
|
-
}
|
|
424
|
+
private resolveAgentPatches(sessionId: string, patches: AgentConstituentaPatch[]): ConstituentaDraft[] {
|
|
425
|
+
const items = this.sessions.get(sessionId).state.items;
|
|
426
|
+
const existingByAlias = new Map(items.map(item => [item.alias, item]));
|
|
427
|
+
let nextId = items.reduce((max, item) => Math.max(max, item.id), 0) + 1;
|
|
191
428
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
429
|
+
return patches.map(patch => {
|
|
430
|
+
const existing = existingByAlias.get(patch.alias);
|
|
431
|
+
const id = patch.id ?? existing?.id ?? nextId++;
|
|
432
|
+
const draft = {
|
|
433
|
+
id,
|
|
434
|
+
alias: patch.alias,
|
|
435
|
+
cstType: patch.cstType ?? existing?.cstType ?? inferCstType(patch.alias),
|
|
436
|
+
definitionFormal: patch.definitionFormal ?? existing?.definitionFormal ?? '',
|
|
437
|
+
term: patch.term ?? existing?.term ?? '',
|
|
438
|
+
definitionText: patch.definitionText ?? existing?.definitionText ?? '',
|
|
439
|
+
convention: patch.convention ?? existing?.convention ?? ''
|
|
440
|
+
};
|
|
441
|
+
existingByAlias.set(patch.alias, {
|
|
442
|
+
...draft,
|
|
443
|
+
analysis: existing?.analysis ?? { success: true, type: null, valueClass: 'value', diagnostics: [] }
|
|
444
|
+
});
|
|
445
|
+
return draft;
|
|
446
|
+
});
|
|
200
447
|
}
|
|
201
448
|
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
449
|
+
private resolveSessionId(sessionId?: string): string {
|
|
450
|
+
const id = sessionId ?? this.currentSessionId;
|
|
451
|
+
if (!id) {
|
|
452
|
+
return this.createSession().sessionId;
|
|
453
|
+
}
|
|
454
|
+
if (!this.sessions.has(id)) {
|
|
455
|
+
if (sessionId) {
|
|
456
|
+
throw new Error(`Unknown session: ${sessionId}`);
|
|
457
|
+
}
|
|
458
|
+
return this.createSession().sessionId;
|
|
459
|
+
}
|
|
460
|
+
return id;
|
|
205
461
|
}
|
|
206
462
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
463
|
+
private trackSession(handle: SessionHandle): SessionHandle {
|
|
464
|
+
this.currentSessionId = handle.sessionId;
|
|
465
|
+
this.sessions.saveCurrentSessionId(handle.sessionId);
|
|
466
|
+
return handle;
|
|
210
467
|
}
|
|
211
468
|
}
|
package/src/models/session.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { type ConstituentaState } from './constituenta';
|
|
2
2
|
import { type SessionModelState } from './model-value';
|
|
3
3
|
|
|
4
|
+
/** Opaque session reference returned by create/import operations. */
|
|
4
5
|
export interface SessionHandle {
|
|
5
6
|
sessionId: string;
|
|
6
7
|
contractVersion: string;
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
/** Recorded checkpoint in session revision history. */
|
|
9
11
|
export interface SessionRevision {
|
|
10
12
|
revisionId: string;
|
|
11
13
|
at: string;
|
|
12
14
|
message?: string;
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
/** Full in-memory session state. */
|
|
15
18
|
export interface SessionState {
|
|
16
19
|
sessionId: string;
|
|
17
20
|
/** Library item alias for the conceptual schema or model. */
|
|
@@ -20,14 +23,14 @@ export interface SessionState {
|
|
|
20
23
|
title: string;
|
|
21
24
|
/** Developer comment (Portal JSON `description` on export). */
|
|
22
25
|
comment: string;
|
|
23
|
-
/**
|
|
26
|
+
/** ISO timestamp of session creation. */
|
|
24
27
|
createdAt: string;
|
|
25
|
-
/**
|
|
28
|
+
/** ISO timestamp of last mutation. */
|
|
26
29
|
updatedAt: string;
|
|
27
|
-
/**
|
|
30
|
+
/** Revision checkpoints recorded via {@link RSToolAgent.commitStep}. */
|
|
28
31
|
revisions: SessionRevision[];
|
|
29
|
-
/**
|
|
32
|
+
/** Analyzed constituents in the conceptual schema. */
|
|
30
33
|
items: ConstituentaState[];
|
|
31
|
-
/**
|
|
34
|
+
/** Evaluated model values. */
|
|
32
35
|
model: SessionModelState;
|
|
33
36
|
}
|