@cynodia/axiom-agent-api 0.12.0-alpha.1 → 0.13.0-alpha.1
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/dist/api.d.ts +9 -0
- package/dist/api.js +11 -0
- package/dist/distributed.d.ts +15 -0
- package/dist/distributed.js +7 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/live-query.d.ts +57 -0
- package/dist/live-query.js +60 -0
- package/package.json +2 -2
package/dist/api.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Transaction } from './transaction.js';
|
|
|
4
4
|
import type { ChangeSet } from './changes.js';
|
|
5
5
|
import type { MigrationImpact, SchemaInspection } from './migration.js';
|
|
6
6
|
import type { DistributedSemanticsInspection } from './distributed.js';
|
|
7
|
+
import type { LiveQueryAnalysis } from './live-query.js';
|
|
7
8
|
/**
|
|
8
9
|
* The machine-facing interface to an application. Agents query semantics and apply
|
|
9
10
|
* structural transformations; they never edit generated code.
|
|
@@ -42,5 +43,13 @@ export declare class AgentAPI extends PresentationQueries {
|
|
|
42
43
|
* `inspectDistributedWork()`.
|
|
43
44
|
*/
|
|
44
45
|
inspectDistributedSemantics(serverContract?: string): DistributedSemanticsInspection;
|
|
46
|
+
/**
|
|
47
|
+
* The live-query semantics of one `QueryDef` (spec13 §38, §148, §149): whether it can be
|
|
48
|
+
* observed live and how (incremental deltas, whole resets, or not at all), the conservative
|
|
49
|
+
* set of committed changes that invalidate it, its row identity field, and what a resume
|
|
50
|
+
* cursor is bound to. Static over the graph; live runtime state is
|
|
51
|
+
* `AxiomServer.inspectLiveQueries()`.
|
|
52
|
+
*/
|
|
53
|
+
analyzeLiveQuery(queryId: string): LiveQueryAnalysis;
|
|
45
54
|
}
|
|
46
55
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.js
CHANGED
|
@@ -3,6 +3,7 @@ import { PresentationQueries } from './presentation-queries.js';
|
|
|
3
3
|
import { Transaction } from './transaction.js';
|
|
4
4
|
import { inspectSchema, migrationImpact } from './migration.js';
|
|
5
5
|
import { inspectDistributedSemantics } from './distributed.js';
|
|
6
|
+
import { analyzeLiveQuery } from './live-query.js';
|
|
6
7
|
/**
|
|
7
8
|
* The machine-facing interface to an application. Agents query semantics and apply
|
|
8
9
|
* structural transformations; they never edit generated code.
|
|
@@ -61,4 +62,14 @@ export class AgentAPI extends PresentationQueries {
|
|
|
61
62
|
inspectDistributedSemantics(serverContract) {
|
|
62
63
|
return inspectDistributedSemantics(this.graph, serverContract);
|
|
63
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* The live-query semantics of one `QueryDef` (spec13 §38, §148, §149): whether it can be
|
|
67
|
+
* observed live and how (incremental deltas, whole resets, or not at all), the conservative
|
|
68
|
+
* set of committed changes that invalidate it, its row identity field, and what a resume
|
|
69
|
+
* cursor is bound to. Static over the graph; live runtime state is
|
|
70
|
+
* `AxiomServer.inspectLiveQueries()`.
|
|
71
|
+
*/
|
|
72
|
+
analyzeLiveQuery(queryId) {
|
|
73
|
+
return analyzeLiveQuery(this.graph, queryId);
|
|
74
|
+
}
|
|
64
75
|
}
|
package/dist/distributed.d.ts
CHANGED
|
@@ -37,11 +37,26 @@ export interface DistributedSemanticsInspection {
|
|
|
37
37
|
note: string;
|
|
38
38
|
};
|
|
39
39
|
workClasses: DistributedWorkClassInfo[];
|
|
40
|
+
/**
|
|
41
|
+
* How a query result cache stays coherent across authorities (spec12 §32-§34).
|
|
42
|
+
*/
|
|
40
43
|
cacheCoherence: {
|
|
41
44
|
mechanism: 'durable-revision-observation';
|
|
42
45
|
stalenessBoundRevisions: 0;
|
|
43
46
|
requiresBroadcast: false;
|
|
44
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* How a running authority's in-memory `StateDef` view stays coherent with state another
|
|
50
|
+
* authority committed (spec12.1 §6-§9, §54). The in-memory view is an authority-local
|
|
51
|
+
* cache; the durable persistence revision is re-observed before every authoritative
|
|
52
|
+
* operation and the view is reloaded when behind.
|
|
53
|
+
*/
|
|
54
|
+
stateCoherence: {
|
|
55
|
+
mechanism: 'durable-revision-observation';
|
|
56
|
+
stalenessBoundRevisions: 0;
|
|
57
|
+
requiresBroadcast: false;
|
|
58
|
+
refreshBeforeAuthoritativeOperation: true;
|
|
59
|
+
};
|
|
45
60
|
operationalTuning: string[];
|
|
46
61
|
}
|
|
47
62
|
/**
|
package/dist/distributed.js
CHANGED
|
@@ -53,7 +53,7 @@ export function inspectDistributedSemantics(graph, serverContract = 'axiom.serve
|
|
|
53
53
|
orderingScope: 'per-subscription',
|
|
54
54
|
delivery: { guarantee: 'at-least-once', duplicatesPossible: true },
|
|
55
55
|
providerCapabilityRequired: ['distributed-lease', 'fencing', 'durable-subscription-cursor', 'event-dedup'],
|
|
56
|
-
runtimeStateAvailableFrom: 'AxiomServer.subscriptionLog()
|
|
56
|
+
runtimeStateAvailableFrom: 'AxiomServer.subscriptionLog()',
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
return {
|
|
@@ -73,6 +73,12 @@ export function inspectDistributedSemantics(graph, serverContract = 'axiom.serve
|
|
|
73
73
|
stalenessBoundRevisions: 0,
|
|
74
74
|
requiresBroadcast: false,
|
|
75
75
|
},
|
|
76
|
+
stateCoherence: {
|
|
77
|
+
mechanism: 'durable-revision-observation',
|
|
78
|
+
stalenessBoundRevisions: 0,
|
|
79
|
+
requiresBroadcast: false,
|
|
80
|
+
refreshBeforeAuthoritativeOperation: true,
|
|
81
|
+
},
|
|
76
82
|
operationalTuning: [
|
|
77
83
|
'instanceId',
|
|
78
84
|
'leaseDurationMs',
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './changes.js';
|
|
|
2
2
|
export * from './queries.js';
|
|
3
3
|
export * from './migration.js';
|
|
4
4
|
export * from './distributed.js';
|
|
5
|
+
export * from './live-query.js';
|
|
5
6
|
export * from './presentation-queries.js';
|
|
6
7
|
export * from './transaction.js';
|
|
7
8
|
export * from './api.js';
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './changes.js';
|
|
|
2
2
|
export * from './queries.js';
|
|
3
3
|
export * from './migration.js';
|
|
4
4
|
export * from './distributed.js';
|
|
5
|
+
export * from './live-query.js';
|
|
5
6
|
export * from './presentation-queries.js';
|
|
6
7
|
export * from './transaction.js';
|
|
7
8
|
export * from './api.js';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type ApplicationGraph, type LiveCapability } from '@cynodia/axiom-core';
|
|
2
|
+
/**
|
|
3
|
+
* Static, graph-derivable live-query analysis (spec13 §38, §148, §149, §189 Q37/Q38).
|
|
4
|
+
*
|
|
5
|
+
* The AgentAPI works over an `ApplicationGraph`, not a running authority, so it answers the
|
|
6
|
+
* *semantic* questions — can this `QueryDef` be observed live, incrementally or only as whole
|
|
7
|
+
* resets, what committed changes invalidate it, and what a resume cursor is bound to — not
|
|
8
|
+
* the live runtime state (that is `AxiomServer.inspectLiveQueries()`).
|
|
9
|
+
*
|
|
10
|
+
* Nothing here names a transport. A live query is a persistent semantic observation of a
|
|
11
|
+
* canonical `QueryDef`; the runtime may poll and the provider may push, but the meaning is
|
|
12
|
+
* fixed by the graph (spec13 §195).
|
|
13
|
+
*/
|
|
14
|
+
export interface LiveQueryAnalysis {
|
|
15
|
+
queryId: string;
|
|
16
|
+
/** `live-capable` (incremental), `live-capable-reset-only` (whole resets), or `not-live-capable`. */
|
|
17
|
+
capability: LiveCapability;
|
|
18
|
+
/** Ordered result — a sort-key change produces an explicit `move` (spec13 §16). */
|
|
19
|
+
ordered: boolean;
|
|
20
|
+
/** Aggregate / grouped — delivered only as `reset` (spec13 §14, §19). */
|
|
21
|
+
aggregate: boolean;
|
|
22
|
+
/** The row identity field the canonical delta model keys on, or `null` for a reset-only query. */
|
|
23
|
+
identityFieldId: string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Conservative static invalidation set (spec13 §26-§31): a committed change to any of these
|
|
26
|
+
* entities or `StateDef`s may move the result. `broad` means the dependency is not
|
|
27
|
+
* statically enumerable, so every commit re-evaluates.
|
|
28
|
+
*/
|
|
29
|
+
dependencies: {
|
|
30
|
+
entityIds: string[];
|
|
31
|
+
stateIds: string[];
|
|
32
|
+
broad: boolean;
|
|
33
|
+
/** The read policy AND-ed into every evaluation, if one governs the source entity. */
|
|
34
|
+
readPolicyId: string | null;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* What a `axiom.live-query-cursor.v1` resume token is bound to — a mismatch on any of these
|
|
38
|
+
* is refused fail-closed on reconnect (spec13 §33-§35, §79-§81).
|
|
39
|
+
*/
|
|
40
|
+
cursorBinding: string[];
|
|
41
|
+
/** The delivery contract, stated honestly (spec13 §33, §41, §85). */
|
|
42
|
+
delivery: {
|
|
43
|
+
guarantee: 'at-least-once-logical';
|
|
44
|
+
updateIdentity: 'subscriptionId + toRevision';
|
|
45
|
+
ordering: 'per-subscription-monotonic-by-revision';
|
|
46
|
+
revisionsMayBeCoalesced: true;
|
|
47
|
+
cursorAcknowledgement: 'server-sent-no-ack';
|
|
48
|
+
};
|
|
49
|
+
/** Present when `capability` is not `live-capable` — why, in one line. */
|
|
50
|
+
reason?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Analyze one `QueryDef`'s live-query semantics. Pure over the graph. Throws if `queryId`
|
|
54
|
+
* does not name a `query` node.
|
|
55
|
+
*/
|
|
56
|
+
export declare function analyzeLiveQuery(graph: ApplicationGraph, queryId: string): LiveQueryAnalysis;
|
|
57
|
+
//# sourceMappingURL=live-query.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { queryDependencies, queryLiveCapability, readPolicyForEntity, } from '@cynodia/axiom-core';
|
|
2
|
+
/**
|
|
3
|
+
* Analyze one `QueryDef`'s live-query semantics. Pure over the graph. Throws if `queryId`
|
|
4
|
+
* does not name a `query` node.
|
|
5
|
+
*/
|
|
6
|
+
export function analyzeLiveQuery(graph, queryId) {
|
|
7
|
+
const query = graph
|
|
8
|
+
.getNodesByKind('query')
|
|
9
|
+
.find((node) => String(node.id) === String(queryId));
|
|
10
|
+
if (!query) {
|
|
11
|
+
throw new Error(`analyzeLiveQuery: no query node "${queryId}"`);
|
|
12
|
+
}
|
|
13
|
+
const entities = graph.getNodesByKind('entity');
|
|
14
|
+
const relationships = graph.getNodesByKind('relationship');
|
|
15
|
+
const readPolicies = graph.getNodesByKind('read-policy');
|
|
16
|
+
const stateIds = new Set(graph.getNodesByKind('state').map((state) => String(state.id)));
|
|
17
|
+
const source = entities.find((entity) => String(entity.id) === String(query.source));
|
|
18
|
+
const sourceIdentityFieldId = source?.identityFieldId ? String(source.identityFieldId) : undefined;
|
|
19
|
+
// Mirror the authority's `policyForQuery`: an explicit `readPolicyId` wins, else the policy
|
|
20
|
+
// that governs the source entity.
|
|
21
|
+
const policy = query.readPolicyId
|
|
22
|
+
? readPolicies.find((candidate) => String(candidate.id) === String(query.readPolicyId))
|
|
23
|
+
: readPolicyForEntity(readPolicies, query.source);
|
|
24
|
+
const capability = queryLiveCapability(query, sourceIdentityFieldId);
|
|
25
|
+
const aggregate = (query.aggregate?.length ?? 0) > 0 || (query.groupBy?.length ?? 0) > 0;
|
|
26
|
+
const ordered = (query.sort?.length ?? 0) > 0;
|
|
27
|
+
const deps = queryDependencies(query, policy, relationships, stateIds);
|
|
28
|
+
const analysis = {
|
|
29
|
+
queryId: String(query.id),
|
|
30
|
+
capability,
|
|
31
|
+
ordered,
|
|
32
|
+
aggregate,
|
|
33
|
+
identityFieldId: capability.capability === 'live-capable' && sourceIdentityFieldId ? sourceIdentityFieldId : null,
|
|
34
|
+
dependencies: {
|
|
35
|
+
entityIds: [...deps.entityIds].sort(),
|
|
36
|
+
stateIds: [...deps.stateIds].sort(),
|
|
37
|
+
broad: deps.broad,
|
|
38
|
+
readPolicyId: policy ? String(policy.id) : null,
|
|
39
|
+
},
|
|
40
|
+
cursorBinding: [
|
|
41
|
+
'queryId',
|
|
42
|
+
'argumentsFingerprint',
|
|
43
|
+
'principalFingerprint',
|
|
44
|
+
'policyFingerprint',
|
|
45
|
+
'compatibilityFingerprint (serverContract + schemaFingerprint + semanticFingerprint)',
|
|
46
|
+
'hmac-sha256 integrity signature',
|
|
47
|
+
],
|
|
48
|
+
delivery: {
|
|
49
|
+
guarantee: 'at-least-once-logical',
|
|
50
|
+
updateIdentity: 'subscriptionId + toRevision',
|
|
51
|
+
ordering: 'per-subscription-monotonic-by-revision',
|
|
52
|
+
revisionsMayBeCoalesced: true,
|
|
53
|
+
cursorAcknowledgement: 'server-sent-no-ack',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
if (capability.capability !== 'live-capable') {
|
|
57
|
+
analysis.reason = capability.reason;
|
|
58
|
+
}
|
|
59
|
+
return analysis;
|
|
60
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cynodia/axiom-agent-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0-alpha.1",
|
|
4
4
|
"description": "Semantic queries and transactional graph transformations for AI agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AskTech AS",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@cynodia/axiom-core": "0.
|
|
34
|
+
"@cynodia/axiom-core": "0.13.0-alpha.1"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc -b tsconfig.json tsconfig.test.json",
|