@xemahq/agent-session-runtime 0.6.6 → 0.7.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 +176 -175
- package/README.md +6 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/dispatch-contract.d.ts +2 -1
- package/dist/lib/dispatch-contract.d.ts.map +1 -1
- package/dist/lib/launch-identity/canonical-contract.d.ts +21 -0
- package/dist/lib/launch-identity/canonical-contract.d.ts.map +1 -0
- package/dist/lib/launch-identity/canonical-contract.js +217 -0
- package/dist/lib/launch-identity/canonical-contract.js.map +1 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan-store.d.ts +44 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan-store.d.ts.map +1 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan-store.js +116 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan-store.js.map +1 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan.d.ts +84 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan.d.ts.map +1 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan.js +386 -0
- package/dist/lib/launch-identity/compiled-session-launch-plan.js.map +1 -0
- package/dist/lib/launch-identity/index.d.ts +7 -0
- package/dist/lib/launch-identity/index.d.ts.map +1 -0
- package/dist/lib/launch-identity/index.js +23 -0
- package/dist/lib/launch-identity/index.js.map +1 -0
- package/dist/lib/launch-identity/runtime-template-key.d.ts +30 -0
- package/dist/lib/launch-identity/runtime-template-key.d.ts.map +1 -0
- package/dist/lib/launch-identity/runtime-template-key.js +73 -0
- package/dist/lib/launch-identity/runtime-template-key.js.map +1 -0
- package/dist/lib/launch-identity/session-binding.d.ts +24 -0
- package/dist/lib/launch-identity/session-binding.d.ts.map +1 -0
- package/dist/lib/launch-identity/session-binding.js +62 -0
- package/dist/lib/launch-identity/session-binding.js.map +1 -0
- package/dist/lib/launch-identity/thread-reuse-key.d.ts +19 -0
- package/dist/lib/launch-identity/thread-reuse-key.d.ts.map +1 -0
- package/dist/lib/launch-identity/thread-reuse-key.js +46 -0
- package/dist/lib/launch-identity/thread-reuse-key.js.map +1 -0
- package/package.json +15 -4
- package/src/index.ts +1 -0
- package/src/lib/agent-workspace-manifest.ts +2 -2
- package/src/lib/composer.ts +2 -2
- package/src/lib/dispatch-contract.ts +4 -9
- package/src/lib/drift-detector.ts +2 -2
- package/src/lib/environment-resolver.ts +3 -3
- package/src/lib/launch-identity/canonical-contract.ts +318 -0
- package/src/lib/launch-identity/compiled-session-launch-plan-store.ts +178 -0
- package/src/lib/launch-identity/compiled-session-launch-plan.ts +689 -0
- package/src/lib/launch-identity/index.ts +6 -0
- package/src/lib/launch-identity/runtime-template-key.ts +148 -0
- package/src/lib/launch-identity/session-binding.ts +152 -0
- package/src/lib/launch-identity/thread-reuse-key.ts +93 -0
- package/src/lib/skill-bundle-template-resolver.ts +1 -1
- package/src/lib/types.ts +1 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSessionBinding = createSessionBinding;
|
|
4
|
+
exports.serializeSessionBinding = serializeSessionBinding;
|
|
5
|
+
exports.hashSessionBinding = hashSessionBinding;
|
|
6
|
+
const canonical_contract_1 = require("./canonical-contract");
|
|
7
|
+
const REQUIRED_KEYS = [
|
|
8
|
+
'schemaVersion',
|
|
9
|
+
'sessionId',
|
|
10
|
+
'organizationId',
|
|
11
|
+
'projectId',
|
|
12
|
+
'userId',
|
|
13
|
+
'domainRefs',
|
|
14
|
+
'storageAllocationRef',
|
|
15
|
+
'workingFileSourceRefs',
|
|
16
|
+
'outputRouteRef',
|
|
17
|
+
'providerTokenRefs',
|
|
18
|
+
'credentialGrantRefs',
|
|
19
|
+
'databaseGrantRefs',
|
|
20
|
+
'dynamicContext',
|
|
21
|
+
'bindingRevision',
|
|
22
|
+
'bindingEpoch',
|
|
23
|
+
];
|
|
24
|
+
const OPTIONAL_KEYS = ['actorTokenRef', 'serviceTokenRef'];
|
|
25
|
+
function createSessionBinding(input) {
|
|
26
|
+
const object = (0, canonical_contract_1.requireExactObject)(input, 'SessionBinding', REQUIRED_KEYS, OPTIONAL_KEYS);
|
|
27
|
+
if (object.schemaVersion !== 1) {
|
|
28
|
+
throw new TypeError('SessionBinding.schemaVersion must be 1.');
|
|
29
|
+
}
|
|
30
|
+
const actorTokenRef = object.actorTokenRef === undefined
|
|
31
|
+
? undefined
|
|
32
|
+
: (0, canonical_contract_1.requireNonEmptyString)(object.actorTokenRef, 'SessionBinding.actorTokenRef');
|
|
33
|
+
const serviceTokenRef = object.serviceTokenRef === undefined
|
|
34
|
+
? undefined
|
|
35
|
+
: (0, canonical_contract_1.requireNonEmptyString)(object.serviceTokenRef, 'SessionBinding.serviceTokenRef');
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
schemaVersion: 1,
|
|
38
|
+
sessionId: (0, canonical_contract_1.requireNonEmptyString)(object.sessionId, 'SessionBinding.sessionId'),
|
|
39
|
+
organizationId: (0, canonical_contract_1.requireNonEmptyString)(object.organizationId, 'SessionBinding.organizationId'),
|
|
40
|
+
projectId: (0, canonical_contract_1.requireNonEmptyString)(object.projectId, 'SessionBinding.projectId'),
|
|
41
|
+
userId: (0, canonical_contract_1.requireNonEmptyString)(object.userId, 'SessionBinding.userId'),
|
|
42
|
+
domainRefs: (0, canonical_contract_1.requireResourceBindingRefs)(object.domainRefs, 'SessionBinding.domainRefs'),
|
|
43
|
+
storageAllocationRef: (0, canonical_contract_1.requireNonEmptyString)(object.storageAllocationRef, 'SessionBinding.storageAllocationRef'),
|
|
44
|
+
workingFileSourceRefs: (0, canonical_contract_1.requireStringRefs)(object.workingFileSourceRefs, 'SessionBinding.workingFileSourceRefs'),
|
|
45
|
+
outputRouteRef: (0, canonical_contract_1.requireNonEmptyString)(object.outputRouteRef, 'SessionBinding.outputRouteRef'),
|
|
46
|
+
...(actorTokenRef === undefined ? {} : { actorTokenRef }),
|
|
47
|
+
...(serviceTokenRef === undefined ? {} : { serviceTokenRef }),
|
|
48
|
+
providerTokenRefs: (0, canonical_contract_1.requireStringRefs)(object.providerTokenRefs, 'SessionBinding.providerTokenRefs'),
|
|
49
|
+
credentialGrantRefs: (0, canonical_contract_1.requireStringRefs)(object.credentialGrantRefs, 'SessionBinding.credentialGrantRefs'),
|
|
50
|
+
databaseGrantRefs: (0, canonical_contract_1.requireStringRefs)(object.databaseGrantRefs, 'SessionBinding.databaseGrantRefs'),
|
|
51
|
+
dynamicContext: (0, canonical_contract_1.requireSecretFreeJsonObject)(object.dynamicContext, 'SessionBinding.dynamicContext'),
|
|
52
|
+
bindingRevision: (0, canonical_contract_1.requireNonEmptyString)(object.bindingRevision, 'SessionBinding.bindingRevision'),
|
|
53
|
+
bindingEpoch: (0, canonical_contract_1.requireNonNegativeSafeInteger)(object.bindingEpoch, 'SessionBinding.bindingEpoch'),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function serializeSessionBinding(input) {
|
|
57
|
+
return (0, canonical_contract_1.canonicalContractJson)(createSessionBinding(input));
|
|
58
|
+
}
|
|
59
|
+
function hashSessionBinding(input) {
|
|
60
|
+
return (0, canonical_contract_1.hashCanonicalContract)(createSessionBinding(input));
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=session-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-binding.js","sourceRoot":"","sources":["../../../src/lib/launch-identity/session-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ResourceBindingRef } from './canonical-contract';
|
|
2
|
+
export declare enum ThreadReusePolicy {
|
|
3
|
+
ExplicitlyShareable = "explicitly-shareable"
|
|
4
|
+
}
|
|
5
|
+
export interface ThreadReuseKey {
|
|
6
|
+
readonly schemaVersion: 1;
|
|
7
|
+
readonly reusePolicy: ThreadReusePolicy.ExplicitlyShareable;
|
|
8
|
+
readonly organizationId: string;
|
|
9
|
+
readonly projectId: string;
|
|
10
|
+
readonly userId: string;
|
|
11
|
+
readonly runtimeTemplateHash: string;
|
|
12
|
+
readonly conversationRef: string;
|
|
13
|
+
readonly workspaceRef: string;
|
|
14
|
+
readonly domainRefs: readonly ResourceBindingRef[];
|
|
15
|
+
}
|
|
16
|
+
export declare function createThreadReuseKey(input: unknown): ThreadReuseKey;
|
|
17
|
+
export declare function serializeThreadReuseKey(input: ThreadReuseKey): string;
|
|
18
|
+
export declare function hashThreadReuseKey(input: ThreadReuseKey): string;
|
|
19
|
+
//# sourceMappingURL=thread-reuse-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-reuse-key.d.ts","sourceRoot":"","sources":["../../../src/lib/launch-identity/thread-reuse-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EAMxB,MAAM,sBAAsB,CAAC;AAE9B,oBAAY,iBAAiB;IAC3B,mBAAmB,yBAAyB;CAC7C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC,mBAAmB,CAAC;IAC5D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACpD;AAmBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAwCnE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAErE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAEhE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThreadReusePolicy = void 0;
|
|
4
|
+
exports.createThreadReuseKey = createThreadReuseKey;
|
|
5
|
+
exports.serializeThreadReuseKey = serializeThreadReuseKey;
|
|
6
|
+
exports.hashThreadReuseKey = hashThreadReuseKey;
|
|
7
|
+
const canonical_contract_1 = require("./canonical-contract");
|
|
8
|
+
var ThreadReusePolicy;
|
|
9
|
+
(function (ThreadReusePolicy) {
|
|
10
|
+
ThreadReusePolicy["ExplicitlyShareable"] = "explicitly-shareable";
|
|
11
|
+
})(ThreadReusePolicy || (exports.ThreadReusePolicy = ThreadReusePolicy = {}));
|
|
12
|
+
const REQUIRED_KEYS = [
|
|
13
|
+
'schemaVersion',
|
|
14
|
+
'reusePolicy',
|
|
15
|
+
'organizationId',
|
|
16
|
+
'projectId',
|
|
17
|
+
'userId',
|
|
18
|
+
'runtimeTemplateHash',
|
|
19
|
+
'conversationRef',
|
|
20
|
+
'workspaceRef',
|
|
21
|
+
'domainRefs',
|
|
22
|
+
];
|
|
23
|
+
function createThreadReuseKey(input) {
|
|
24
|
+
const object = (0, canonical_contract_1.requireExactObject)(input, 'ThreadReuseKey', REQUIRED_KEYS);
|
|
25
|
+
if (object.schemaVersion !== 1) {
|
|
26
|
+
throw new TypeError('ThreadReuseKey.schemaVersion must be 1.');
|
|
27
|
+
}
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
schemaVersion: 1,
|
|
30
|
+
reusePolicy: (0, canonical_contract_1.requireEnumValue)(object.reusePolicy, 'ThreadReuseKey.reusePolicy', [ThreadReusePolicy.ExplicitlyShareable]),
|
|
31
|
+
organizationId: (0, canonical_contract_1.requireNonEmptyString)(object.organizationId, 'ThreadReuseKey.organizationId'),
|
|
32
|
+
projectId: (0, canonical_contract_1.requireNonEmptyString)(object.projectId, 'ThreadReuseKey.projectId'),
|
|
33
|
+
userId: (0, canonical_contract_1.requireNonEmptyString)(object.userId, 'ThreadReuseKey.userId'),
|
|
34
|
+
runtimeTemplateHash: (0, canonical_contract_1.requireSha256)(object.runtimeTemplateHash, 'ThreadReuseKey.runtimeTemplateHash'),
|
|
35
|
+
conversationRef: (0, canonical_contract_1.requireNonEmptyString)(object.conversationRef, 'ThreadReuseKey.conversationRef'),
|
|
36
|
+
workspaceRef: (0, canonical_contract_1.requireNonEmptyString)(object.workspaceRef, 'ThreadReuseKey.workspaceRef'),
|
|
37
|
+
domainRefs: (0, canonical_contract_1.requireResourceBindingRefs)(object.domainRefs, 'ThreadReuseKey.domainRefs'),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function serializeThreadReuseKey(input) {
|
|
41
|
+
return (0, canonical_contract_1.canonicalContractJson)(createThreadReuseKey(input));
|
|
42
|
+
}
|
|
43
|
+
function hashThreadReuseKey(input) {
|
|
44
|
+
return (0, canonical_contract_1.hashCanonicalContract)(createThreadReuseKey(input));
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=thread-reuse-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-reuse-key.js","sourceRoot":"","sources":["../../../src/lib/launch-identity/thread-reuse-key.ts"],"names":[],"mappings":";;;AA4CA,oDAwCC;AAED,0DAEC;AAED,gDAEC;AA5FD,6DAS8B;AAE9B,IAAY,iBAEX;AAFD,WAAY,iBAAiB;IAC3B,iEAA4C,CAAA;AAC9C,CAAC,EAFW,iBAAiB,iCAAjB,iBAAiB,QAE5B;AAcD,MAAM,aAAa,GAAG;IACpB,eAAe;IACf,aAAa;IACb,gBAAgB;IAChB,WAAW;IACX,QAAQ;IACR,qBAAqB;IACrB,iBAAiB;IACjB,cAAc;IACd,YAAY;CACJ,CAAC;AAOX,SAAgB,oBAAoB,CAAC,KAAc;IACjD,MAAM,MAAM,GAAG,IAAA,uCAAkB,EAAC,KAAK,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAC;IAE1E,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,IAAA,qCAAgB,EAC3B,MAAM,CAAC,WAAW,EAClB,4BAA4B,EAC5B,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CACxC;QACD,cAAc,EAAE,IAAA,0CAAqB,EACnC,MAAM,CAAC,cAAc,EACrB,+BAA+B,CAChC;QACD,SAAS,EAAE,IAAA,0CAAqB,EAC9B,MAAM,CAAC,SAAS,EAChB,0BAA0B,CAC3B;QACD,MAAM,EAAE,IAAA,0CAAqB,EAAC,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC;QACrE,mBAAmB,EAAE,IAAA,kCAAa,EAChC,MAAM,CAAC,mBAAmB,EAC1B,oCAAoC,CACrC;QACD,eAAe,EAAE,IAAA,0CAAqB,EACpC,MAAM,CAAC,eAAe,EACtB,gCAAgC,CACjC;QACD,YAAY,EAAE,IAAA,0CAAqB,EACjC,MAAM,CAAC,YAAY,EACnB,6BAA6B,CAC9B;QACD,UAAU,EAAE,IAAA,+CAA0B,EACpC,MAAM,CAAC,UAAU,EACjB,2BAA2B,CAC5B;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,uBAAuB,CAAC,KAAqB;IAC3D,OAAO,IAAA,0CAAqB,EAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAAqB;IACtD,OAAO,IAAA,0CAAqB,EAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/agent-session-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Runtime for composing and running Xema agent sessions — workspace manifests, skill bundles, environment resolution, and drift detection.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Neuralchowder Inc. <developer@xema.dev> (https://xema.dev)",
|
|
7
|
+
"homepage": "https://xema.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/xema-dev/xema-runtime-core.git",
|
|
11
|
+
"directory": "packages/runtime/agent-session-runtime"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/xema-dev/xema-runtime-core/issues",
|
|
4
14
|
"publishConfig": {
|
|
5
15
|
"registry": "https://registry.npmjs.org/",
|
|
6
16
|
"access": "public"
|
|
@@ -35,11 +45,12 @@
|
|
|
35
45
|
"prettier": "3.6.2",
|
|
36
46
|
"ts-jest": "^29.4.9",
|
|
37
47
|
"typescript": "5.9.3",
|
|
38
|
-
"@xemahq/kernel-contracts": "^0.
|
|
48
|
+
"@xemahq/kernel-contracts": "^0.60.0"
|
|
39
49
|
},
|
|
40
50
|
"dependencies": {
|
|
41
|
-
"@xemahq/
|
|
42
|
-
"@xemahq/
|
|
51
|
+
"@xemahq/declarative-reconciler": "^0.1.1",
|
|
52
|
+
"@xemahq/dsl": "^0.6.1",
|
|
53
|
+
"@xemahq/kernel-contracts": "^0.60.0"
|
|
43
54
|
},
|
|
44
55
|
"peerDependencies": {
|
|
45
56
|
"@xemahq/kernel-contracts": ">=0.13.0"
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
2
|
// ── Agent → CompiledWorkspaceManifest reconstruction ──
|
|
3
3
|
//
|
|
4
|
-
//
|
|
4
|
+
// The composer turns a
|
|
5
5
|
// `CompiledWorkspaceManifest` into a `WorkspaceMountPlan`; before this
|
|
6
6
|
// module the only way to obtain that compiled manifest was to fetch the
|
|
7
7
|
// `WorkspaceManifest` row from `workspace-manifests-api` and run
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
type ManifestSeedFile,
|
|
48
48
|
type ManifestSubAgent,
|
|
49
49
|
type ManifestWorkingFile,
|
|
50
|
-
type
|
|
50
|
+
type AgentWorkspaceSpec as DslWorkspaceManifest,
|
|
51
51
|
type WorkspaceManifestSpec,
|
|
52
52
|
} from '@xemahq/dsl/workspace-manifest';
|
|
53
53
|
|
package/src/lib/composer.ts
CHANGED
|
@@ -328,8 +328,8 @@ export class DefaultWorkspaceImageComposer implements WorkspaceImageComposer {
|
|
|
328
328
|
// `/<skillKey>` in a session loads and applies that skill natively.
|
|
329
329
|
//
|
|
330
330
|
// Kernel-shipped System skills are PREPENDED to whatever skills the
|
|
331
|
-
// caller already named in `agentContext.skills` (
|
|
332
|
-
//
|
|
331
|
+
// caller already named in `agentContext.skills` (per the skill
|
|
332
|
+
// composition rules — `SkillSpace.System`
|
|
333
333
|
// skills are auto-injected into every agent's mounted bundle).
|
|
334
334
|
// `dedupe` collapses any overlap so a caller that re-mentions a
|
|
335
335
|
// System skill in `agentContext.skills` does not double-mount it.
|
|
@@ -83,15 +83,10 @@ export interface CreateAndRunDispatch {
|
|
|
83
83
|
readonly jobRunId: string;
|
|
84
84
|
/** Stable spine identity within the workflow run. */
|
|
85
85
|
readonly jobKey: string;
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
* lifecycle resolves it via llm-registry-api's `GET /compositions/
|
|
91
|
-
* resolve/:ref` for both the agent/skill/tool tree and the workspace
|
|
92
|
-
* mount layout.
|
|
93
|
-
*/
|
|
94
|
-
readonly agentRef: string;
|
|
86
|
+
/** Immutable AgentRevision selected by workflow resolution. */
|
|
87
|
+
readonly agentRevisionId: string;
|
|
88
|
+
/** SHA-256 of the selected AgentRevision content. */
|
|
89
|
+
readonly agentContentHash: string;
|
|
95
90
|
readonly agentSlug: string;
|
|
96
91
|
readonly promptContext: DispatchPromptContext;
|
|
97
92
|
}
|
|
@@ -57,8 +57,8 @@ export enum DriftKind {
|
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* Advisory drift severity — `info` (benign) or `warning` (worth a look).
|
|
60
|
-
* There is deliberately no `critical`: resume is non-blocking by design
|
|
61
|
-
*
|
|
60
|
+
* There is deliberately no `critical`: resume is non-blocking by design,
|
|
61
|
+
* so severity only drives how the operator's drift
|
|
62
62
|
* toast renders, never whether the session resumes.
|
|
63
63
|
*/
|
|
64
64
|
export type DriftSeverity = 'info' | 'warning';
|
|
@@ -124,7 +124,7 @@ export interface EnvironmentResolverRequest {
|
|
|
124
124
|
*/
|
|
125
125
|
readonly systemSkillSlugs?: readonly string[];
|
|
126
126
|
/**
|
|
127
|
-
* Optional MCP stanza resolver
|
|
127
|
+
* Optional MCP stanza resolver. Translates the manifest's
|
|
128
128
|
* `toolSelection` into a `mcpServers` map suitable for direct write
|
|
129
129
|
* into `opencode.jsonc:mcp`. When absent, the resolved environment
|
|
130
130
|
* carries no MCP stanzas — appropriate for workflow surfaces today
|
|
@@ -205,7 +205,7 @@ export interface ResolvedEnvironment {
|
|
|
205
205
|
readonly mountPlan: WorkspaceMountPlan;
|
|
206
206
|
readonly env: readonly { readonly name: string; readonly value: string }[];
|
|
207
207
|
/**
|
|
208
|
-
*
|
|
208
|
+
* Resolved `mcpServers` map ready to drop into
|
|
209
209
|
* `opencode.jsonc:mcp`. Empty `{}` when the manifest declares no
|
|
210
210
|
* toolSelection or when the request omits an `mcpResolver`. Keeps
|
|
211
211
|
* the snapshot self-contained so downstream callers (workflow
|
|
@@ -279,7 +279,7 @@ export class DefaultEnvironmentResolver implements EnvironmentResolver {
|
|
|
279
279
|
req.briefcase?.mcpTools,
|
|
280
280
|
);
|
|
281
281
|
|
|
282
|
-
//
|
|
282
|
+
// Capability federation. When an `mcpResolver` is wired
|
|
283
283
|
// (session-boot, workflow-runtime-worker) the resolver ALWAYS runs —
|
|
284
284
|
// the returned stanza is the fixed three meta-tool surface
|
|
285
285
|
// (`xema-capabilities-{list,describe,invoke}`), regardless of
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { canonicalJson, stableHash } from '@xemahq/declarative-reconciler';
|
|
2
|
+
|
|
3
|
+
export type CanonicalJsonValue =
|
|
4
|
+
| boolean
|
|
5
|
+
| number
|
|
6
|
+
| string
|
|
7
|
+
| null
|
|
8
|
+
| readonly CanonicalJsonValue[]
|
|
9
|
+
| { readonly [key: string]: CanonicalJsonValue };
|
|
10
|
+
|
|
11
|
+
export interface ResourceBindingRef {
|
|
12
|
+
readonly kind: string;
|
|
13
|
+
readonly ref: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const SHA256_PATTERN = /^[a-f0-9]{64}$/u;
|
|
17
|
+
const SECRET_FIELD_PATTERN =
|
|
18
|
+
/(?:^|[_-])(api[_-]?key|authorization|cookie|credential|password|private[_-]?key|secret|token)(?:$|[_-])/iu;
|
|
19
|
+
const SECRET_CAMEL_CASE_PATTERN =
|
|
20
|
+
/(?:apiKey|authorization|cookie|credential|password|privateKey|secret|token)/u;
|
|
21
|
+
const SECRET_REFERENCE_SUFFIX_PATTERN = /Refs?$/u;
|
|
22
|
+
|
|
23
|
+
export function canonicalContractJson(value: unknown): string {
|
|
24
|
+
return canonicalJson(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function hashCanonicalContract(value: unknown): string {
|
|
28
|
+
return stableHash(value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function requireExactObject(
|
|
32
|
+
value: unknown,
|
|
33
|
+
path: string,
|
|
34
|
+
requiredKeys: readonly string[],
|
|
35
|
+
optionalKeys: readonly string[] = [],
|
|
36
|
+
): Readonly<Record<string, unknown>> {
|
|
37
|
+
if (!isPlainObject(value)) {
|
|
38
|
+
throw new TypeError(`${path} must be a plain object.`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const allowedKeys = new Set([...requiredKeys, ...optionalKeys]);
|
|
42
|
+
for (const key of Object.keys(value)) {
|
|
43
|
+
if (!allowedKeys.has(key)) {
|
|
44
|
+
throw new TypeError(`${path}.${key} is not a supported field.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const key of requiredKeys) {
|
|
49
|
+
if (!Object.hasOwn(value, key)) {
|
|
50
|
+
throw new TypeError(`${path}.${key} is required.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function requireNonEmptyString(value: unknown, path: string): string {
|
|
58
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
59
|
+
throw new TypeError(`${path} must be a non-empty string.`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function requireBoolean(value: unknown, path: string): boolean {
|
|
65
|
+
if (typeof value !== 'boolean') {
|
|
66
|
+
throw new TypeError(`${path} must be a boolean.`);
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function requireSha256(value: unknown, path: string): string {
|
|
72
|
+
const hash = requireNonEmptyString(value, path);
|
|
73
|
+
if (!SHA256_PATTERN.test(hash)) {
|
|
74
|
+
throw new TypeError(`${path} must be a lowercase SHA-256 hex digest.`);
|
|
75
|
+
}
|
|
76
|
+
return hash;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function requireNonNegativeSafeInteger(
|
|
80
|
+
value: unknown,
|
|
81
|
+
path: string,
|
|
82
|
+
): number {
|
|
83
|
+
if (!Number.isSafeInteger(value) || (value as number) < 0) {
|
|
84
|
+
throw new TypeError(`${path} must be a non-negative safe integer.`);
|
|
85
|
+
}
|
|
86
|
+
return value as number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function requireEnumValue<T extends string>(
|
|
90
|
+
value: unknown,
|
|
91
|
+
path: string,
|
|
92
|
+
values: readonly T[],
|
|
93
|
+
): T {
|
|
94
|
+
if (typeof value !== 'string' || !values.includes(value as T)) {
|
|
95
|
+
throw new TypeError(
|
|
96
|
+
`${path} must be one of: ${values.map((entry) => `'${entry}'`).join(', ')}.`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return value as T;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function requireStringRefs(
|
|
103
|
+
value: unknown,
|
|
104
|
+
path: string,
|
|
105
|
+
): readonly string[] {
|
|
106
|
+
if (!Array.isArray(value)) {
|
|
107
|
+
throw new TypeError(`${path} must be an array.`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return Object.freeze(
|
|
111
|
+
[
|
|
112
|
+
...new Set(
|
|
113
|
+
value.map((entry, index) =>
|
|
114
|
+
requireNonEmptyString(entry, `${path}[${index}]`),
|
|
115
|
+
),
|
|
116
|
+
),
|
|
117
|
+
].sort(),
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function requireResourceBindingRefs(
|
|
122
|
+
value: unknown,
|
|
123
|
+
path: string,
|
|
124
|
+
): readonly ResourceBindingRef[] {
|
|
125
|
+
if (!Array.isArray(value)) {
|
|
126
|
+
throw new TypeError(`${path} must be an array.`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const refs = value.map((entry, index) => {
|
|
130
|
+
const entryPath = `${path}[${index}]`;
|
|
131
|
+
const object = requireExactObject(entry, entryPath, ['kind', 'ref']);
|
|
132
|
+
return Object.freeze({
|
|
133
|
+
kind: requireNonEmptyString(object.kind, `${entryPath}.kind`),
|
|
134
|
+
ref: requireNonEmptyString(object.ref, `${entryPath}.ref`),
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const byCanonicalRef = new Map(
|
|
139
|
+
refs.map((entry) => [canonicalJson(entry), entry] as const),
|
|
140
|
+
);
|
|
141
|
+
return Object.freeze(
|
|
142
|
+
[...byCanonicalRef.entries()]
|
|
143
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
144
|
+
.map(([, entry]) => entry),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function requireSecretFreeJsonObject(
|
|
149
|
+
value: unknown,
|
|
150
|
+
path: string,
|
|
151
|
+
): Readonly<Record<string, CanonicalJsonValue>> {
|
|
152
|
+
const normalized = normalizeCanonicalJson(value, path, true);
|
|
153
|
+
if (
|
|
154
|
+
normalized === null ||
|
|
155
|
+
Array.isArray(normalized) ||
|
|
156
|
+
typeof normalized !== 'object'
|
|
157
|
+
) {
|
|
158
|
+
throw new TypeError(`${path} must be a plain JSON object.`);
|
|
159
|
+
}
|
|
160
|
+
return normalized as Readonly<Record<string, CanonicalJsonValue>>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function requireCanonicalJsonObject(
|
|
164
|
+
value: unknown,
|
|
165
|
+
path: string,
|
|
166
|
+
): Readonly<Record<string, CanonicalJsonValue>> {
|
|
167
|
+
const normalized = normalizeCanonicalJson(value, path, false);
|
|
168
|
+
if (
|
|
169
|
+
normalized === null ||
|
|
170
|
+
Array.isArray(normalized) ||
|
|
171
|
+
typeof normalized !== 'object'
|
|
172
|
+
) {
|
|
173
|
+
throw new TypeError(`${path} must be a plain JSON object.`);
|
|
174
|
+
}
|
|
175
|
+
return normalized as Readonly<Record<string, CanonicalJsonValue>>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function assertNoTenantOrSecretTemplateFields(
|
|
179
|
+
value: unknown,
|
|
180
|
+
path: string,
|
|
181
|
+
): void {
|
|
182
|
+
const visited = new Set<object>();
|
|
183
|
+
|
|
184
|
+
function inspect(current: unknown, currentPath: string): void {
|
|
185
|
+
if (current === null || typeof current !== 'object') {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (visited.has(current)) {
|
|
189
|
+
throw new TypeError(`${currentPath} must not contain cycles.`);
|
|
190
|
+
}
|
|
191
|
+
visited.add(current);
|
|
192
|
+
|
|
193
|
+
if (Array.isArray(current)) {
|
|
194
|
+
current.forEach((entry, index) =>
|
|
195
|
+
inspect(entry, `${currentPath}[${index}]`),
|
|
196
|
+
);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!isPlainObject(current)) {
|
|
200
|
+
throw new TypeError(`${currentPath} must contain only plain objects.`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
for (const [key, entry] of Object.entries(current)) {
|
|
204
|
+
if (isTenantField(key) || isSecretField(key)) {
|
|
205
|
+
throw new TypeError(
|
|
206
|
+
`${currentPath}.${key} is tenant/session/secret state and cannot enter a RuntimeTemplateKey.`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
inspect(entry, `${currentPath}.${key}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
inspect(value, path);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function normalizeCanonicalJson(
|
|
217
|
+
value: unknown,
|
|
218
|
+
path: string,
|
|
219
|
+
rejectSecretFields: boolean,
|
|
220
|
+
visited = new Set<object>(),
|
|
221
|
+
): CanonicalJsonValue {
|
|
222
|
+
if (
|
|
223
|
+
value === null ||
|
|
224
|
+
typeof value === 'string' ||
|
|
225
|
+
typeof value === 'boolean'
|
|
226
|
+
) {
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
if (typeof value === 'number') {
|
|
230
|
+
if (!Number.isFinite(value)) {
|
|
231
|
+
throw new TypeError(`${path} must contain only finite numbers.`);
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
if (typeof value !== 'object') {
|
|
236
|
+
throw new TypeError(`${path} must contain only JSON values.`);
|
|
237
|
+
}
|
|
238
|
+
if (visited.has(value)) {
|
|
239
|
+
throw new TypeError(`${path} must not contain cycles.`);
|
|
240
|
+
}
|
|
241
|
+
visited.add(value);
|
|
242
|
+
|
|
243
|
+
if (Array.isArray(value)) {
|
|
244
|
+
const normalized = value.map((entry, index) =>
|
|
245
|
+
normalizeCanonicalJson(
|
|
246
|
+
entry,
|
|
247
|
+
`${path}[${index}]`,
|
|
248
|
+
rejectSecretFields,
|
|
249
|
+
visited,
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
visited.delete(value);
|
|
253
|
+
return Object.freeze(normalized);
|
|
254
|
+
}
|
|
255
|
+
if (!isPlainObject(value)) {
|
|
256
|
+
throw new TypeError(`${path} must contain only plain JSON objects.`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const normalized: Record<string, CanonicalJsonValue> = {};
|
|
260
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
261
|
+
if (
|
|
262
|
+
rejectSecretFields &&
|
|
263
|
+
isSecretField(key) &&
|
|
264
|
+
!SECRET_REFERENCE_SUFFIX_PATTERN.test(key)
|
|
265
|
+
) {
|
|
266
|
+
throw new TypeError(
|
|
267
|
+
`${path}.${key} appears to contain secret material; pass an opaque reference ending in Ref or Refs instead.`,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
normalized[key] = normalizeCanonicalJson(
|
|
271
|
+
entry,
|
|
272
|
+
`${path}.${key}`,
|
|
273
|
+
rejectSecretFields,
|
|
274
|
+
visited,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
visited.delete(value);
|
|
278
|
+
return Object.freeze(normalized);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function isTenantField(key: string): boolean {
|
|
282
|
+
const normalized = key.replaceAll(/[_-]/gu, '').toLowerCase();
|
|
283
|
+
return [
|
|
284
|
+
'binding',
|
|
285
|
+
'context',
|
|
286
|
+
'domain',
|
|
287
|
+
'domainid',
|
|
288
|
+
'input',
|
|
289
|
+
'organization',
|
|
290
|
+
'organizationid',
|
|
291
|
+
'org',
|
|
292
|
+
'orgid',
|
|
293
|
+
'project',
|
|
294
|
+
'projectid',
|
|
295
|
+
'session',
|
|
296
|
+
'sessionid',
|
|
297
|
+
'tenant',
|
|
298
|
+
'tenantid',
|
|
299
|
+
'thread',
|
|
300
|
+
'threadid',
|
|
301
|
+
'user',
|
|
302
|
+
'userid',
|
|
303
|
+
].includes(normalized);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function isSecretField(key: string): boolean {
|
|
307
|
+
return SECRET_FIELD_PATTERN.test(key) || SECRET_CAMEL_CASE_PATTERN.test(key);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function isPlainObject(
|
|
311
|
+
value: unknown,
|
|
312
|
+
): value is Readonly<Record<string, unknown>> {
|
|
313
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const prototype = Object.getPrototypeOf(value);
|
|
317
|
+
return prototype === Object.prototype || prototype === null;
|
|
318
|
+
}
|