@xemahq/agent-session-runtime 0.11.1 → 0.12.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.
@@ -1,93 +0,0 @@
1
- import {
2
- canonicalContractJson,
3
- hashCanonicalContract,
4
- type ResourceBindingRef,
5
- requireEnumValue,
6
- requireExactObject,
7
- requireNonEmptyString,
8
- requireResourceBindingRefs,
9
- requireSha256,
10
- } from './canonical-contract';
11
-
12
- export enum ThreadReusePolicy {
13
- ExplicitlyShareable = 'explicitly-shareable',
14
- }
15
-
16
- export interface ThreadReuseKey {
17
- readonly schemaVersion: 1;
18
- readonly reusePolicy: ThreadReusePolicy.ExplicitlyShareable;
19
- readonly organizationId: string;
20
- readonly projectId: string;
21
- readonly userId: string;
22
- readonly runtimeTemplateHash: string;
23
- readonly conversationRef: string;
24
- readonly workspaceRef: string;
25
- readonly domainRefs: readonly ResourceBindingRef[];
26
- }
27
-
28
- const REQUIRED_KEYS = [
29
- 'schemaVersion',
30
- 'reusePolicy',
31
- 'organizationId',
32
- 'projectId',
33
- 'userId',
34
- 'runtimeTemplateHash',
35
- 'conversationRef',
36
- 'workspaceRef',
37
- 'domainRefs',
38
- ] as const;
39
-
40
- /**
41
- * Canonical identity for the deliberately narrower same-user conversation and
42
- * filesystem reuse decision. A RuntimeTemplateKey match alone never permits
43
- * Thread reuse.
44
- */
45
- export function createThreadReuseKey(input: unknown): ThreadReuseKey {
46
- const object = requireExactObject(input, 'ThreadReuseKey', REQUIRED_KEYS);
47
-
48
- if (object.schemaVersion !== 1) {
49
- throw new TypeError('ThreadReuseKey.schemaVersion must be 1.');
50
- }
51
-
52
- return Object.freeze({
53
- schemaVersion: 1,
54
- reusePolicy: requireEnumValue(
55
- object.reusePolicy,
56
- 'ThreadReuseKey.reusePolicy',
57
- [ThreadReusePolicy.ExplicitlyShareable],
58
- ),
59
- organizationId: requireNonEmptyString(
60
- object.organizationId,
61
- 'ThreadReuseKey.organizationId',
62
- ),
63
- projectId: requireNonEmptyString(
64
- object.projectId,
65
- 'ThreadReuseKey.projectId',
66
- ),
67
- userId: requireNonEmptyString(object.userId, 'ThreadReuseKey.userId'),
68
- runtimeTemplateHash: requireSha256(
69
- object.runtimeTemplateHash,
70
- 'ThreadReuseKey.runtimeTemplateHash',
71
- ),
72
- conversationRef: requireNonEmptyString(
73
- object.conversationRef,
74
- 'ThreadReuseKey.conversationRef',
75
- ),
76
- workspaceRef: requireNonEmptyString(
77
- object.workspaceRef,
78
- 'ThreadReuseKey.workspaceRef',
79
- ),
80
- domainRefs: requireResourceBindingRefs(
81
- object.domainRefs,
82
- 'ThreadReuseKey.domainRefs',
83
- ),
84
- });
85
- }
86
-
87
- export function serializeThreadReuseKey(input: ThreadReuseKey): string {
88
- return canonicalContractJson(createThreadReuseKey(input));
89
- }
90
-
91
- export function hashThreadReuseKey(input: ThreadReuseKey): string {
92
- return hashCanonicalContract(createThreadReuseKey(input));
93
- }
@@ -1,30 +0,0 @@
1
- // ═══════════════════════════════════════════════════════════════════════════
2
- // ── Agent-session lifecycle state machine — re-export of the kernel SSOT ──
3
- //
4
- // This file is a thin re-export surface. The closed `SessionLifecycleState` /
5
- // `SessionOwnerKind` value sets, the transition FSM (`canTransition`), and the
6
- // `isTerminal` / `isPausable` / `isResumable` predicates are the canonical
7
- // Layer-0 contract owned by `@xemahq/kernel-contracts/agent-session`. The former
8
- // hand-maintained copy that lived here was collapsed into that single source of
9
- // truth; this module is retained ONLY so the package's public surface
10
- // (re-exported from `src/index.ts`) is unchanged.
11
- //
12
- // Prisma cannot import a TS value, so the agent-session-api schema re-declares
13
- // the same members and CI guards parity
14
- // (`tooling/boundaries/check-session-enum-parity.mjs`).
15
- // ═══════════════════════════════════════════════════════════════════════════
16
-
17
- export {
18
- SessionLifecycleState,
19
- SessionOwnerKind,
20
- canTransition,
21
- isTerminal,
22
- isPausable,
23
- isResumable,
24
- SessionLifecycleStateSchema,
25
- SessionOwnerKindSchema,
26
- } from '@xemahq/kernel-contracts/agent-session';
27
- export type {
28
- SessionLifecycleStateValue,
29
- SessionOwnerKindValue,
30
- } from '@xemahq/kernel-contracts/agent-session';
@@ -1,147 +0,0 @@
1
- // ═══════════════════════════════════════════════════════════════════════════
2
- // ── Skill-bundle-backed TemplateResolver ──
3
- //
4
- // Seed-file templates used to
5
- // live in `workspace-manifests-api` (the `workspace_manifest_templates` table)
6
- // and were fetched by name. They are now SKILL-BUNDLE RESOURCES served by
7
- // `skill-registry-api` (`GET /skills/bundle`): a biome that ships templates
8
- // packages them inside a skill bundle under `assets/templates/<name>.hbs`.
9
- //
10
- // This factory builds a `TemplateResolver` that:
11
- // 1. Walks the resolved composition's skill set.
12
- // 2. Fetches each skill bundle through the injected `fetchBundle` function.
13
- // 3. Locates the requested template by mapping the bare template name
14
- // (`demo-seeded-canvas-index.html`) to the resource relPath
15
- // (`assets/templates/demo-seeded-canvas-index.html.hbs`).
16
- // 4. Compiles the raw template via the injected `compileTemplate` function
17
- // and renders it with the seed-file `vars`.
18
- //
19
- // Both the bundle-fetch and the Handlebars compile are INJECTED so this
20
- // Kernel package stays free of an HTTP client and a templating dependency —
21
- // `agent-session-api` (and, after Step 4, `workflow-runtime-worker`) supply
22
- // the concrete implementations and share this one resolution algorithm.
23
- // ═══════════════════════════════════════════════════════════════════════════
24
-
25
- import type { TemplateResolver } from './types';
26
-
27
- /** The `assets/templates/` directory prefix every template resource sits under. */
28
- const TEMPLATE_RESOURCE_PREFIX = 'assets/templates/';
29
- /** The file extension a Handlebars template resource carries inside the bundle. */
30
- const TEMPLATE_RESOURCE_SUFFIX = '.hbs';
31
-
32
- /**
33
- * One resource inside a skill bundle. Mirrors `SkillBundleResourceDto` from
34
- * the skill-registry-api client without importing it (Kernel stays
35
- * client-dep-free).
36
- */
37
- export interface SkillBundleResource {
38
- /** Forward-slash path relative to the skill directory. */
39
- readonly relPath: string;
40
- /** File bytes, base64-encoded. */
41
- readonly content: string;
42
- }
43
-
44
- /**
45
- * The slice of a skill bundle this resolver needs. Mirrors
46
- * `SkillBundleResponseDto` (subset).
47
- */
48
- export interface SkillBundle {
49
- readonly slug: string;
50
- readonly resources: readonly SkillBundleResource[];
51
- }
52
-
53
- /**
54
- * Fetches one skill bundle by slug. Implemented by the consumer with its
55
- * `skill-registry-api` Orval client. Must reject (not return null) on a
56
- * missing bundle — a template referencing a skill that does not resolve is
57
- * a fail-fast condition.
58
- */
59
- export type SkillBundleFetcher = (slug: string) => Promise<SkillBundle>;
60
-
61
- /**
62
- * Compiles a raw template string and renders it with `vars`. Injected so
63
- * the Kernel package does not depend on a concrete templating library.
64
- */
65
- export type TemplateCompiler = (
66
- source: string,
67
- vars: Readonly<Record<string, unknown>>,
68
- ) => string;
69
-
70
- /** Raised when a referenced seed-file template cannot be resolved. */
71
- export class SkillBundleTemplateNotFoundError extends Error {
72
- constructor(
73
- public readonly templateName: string,
74
- public readonly skillSlugs: readonly string[],
75
- ) {
76
- super(
77
- `Seed-file template "${templateName}" was not found as ` +
78
- `"${TEMPLATE_RESOURCE_PREFIX}${templateName}${TEMPLATE_RESOURCE_SUFFIX}" ` +
79
- `in any of the composition's skill bundles ` +
80
- `[${skillSlugs.join(', ') || '<none>'}]. The biome that owns the ` +
81
- `template must ship it inside a skill bundle the composition references.`,
82
- );
83
- this.name = 'SkillBundleTemplateNotFoundError';
84
- }
85
- }
86
-
87
- /**
88
- * Map a bare seed-file template name to its skill-bundle resource relPath.
89
- * `demo-seeded-canvas-index.html` → `assets/templates/demo-seeded-canvas-index.html.hbs`.
90
- */
91
- export function templateResourceRelPath(templateName: string): string {
92
- return `${TEMPLATE_RESOURCE_PREFIX}${templateName}${TEMPLATE_RESOURCE_SUFFIX}`;
93
- }
94
-
95
- /**
96
- * Build a `TemplateResolver` backed by the resolved composition's skill
97
- * bundles.
98
- *
99
- * `skillSlugs` is the set of skill slugs attached to the resolved
100
- * composition (root node + descendants). Bundles are fetched lazily and
101
- * memoised for the lifetime of the returned resolver, so a session whose
102
- * manifest references three templates from one skill fetches that bundle
103
- * exactly once.
104
- *
105
- * Fail-fast: a `fetchBundle` rejection propagates; a template name that
106
- * matches no resource in any bundle throws `SkillBundleTemplateNotFoundError`.
107
- */
108
- export function buildSkillBundleTemplateResolver(params: {
109
- readonly skillSlugs: readonly string[];
110
- readonly fetchBundle: SkillBundleFetcher;
111
- readonly compileTemplate: TemplateCompiler;
112
- }): TemplateResolver {
113
- const { skillSlugs, fetchBundle, compileTemplate } = params;
114
- // De-duplicate so the same skill referenced at multiple nodes is fetched once.
115
- const uniqueSlugs = [...new Set(skillSlugs)];
116
- const bundleCache = new Map<string, Promise<SkillBundle>>();
117
-
118
- const loadBundle = (slug: string): Promise<SkillBundle> => {
119
- const cached = bundleCache.get(slug);
120
- if (cached) {
121
- return cached;
122
- }
123
- const pending = fetchBundle(slug);
124
- bundleCache.set(slug, pending);
125
- return pending;
126
- };
127
-
128
- return {
129
- async resolve(
130
- name: string,
131
- vars: Readonly<Record<string, unknown>>,
132
- ): Promise<string> {
133
- const relPath = templateResourceRelPath(name);
134
- for (const slug of uniqueSlugs) {
135
- const bundle = await loadBundle(slug);
136
- const resource = bundle.resources.find((r) => r.relPath === relPath);
137
- if (resource) {
138
- const source = Buffer.from(resource.content, 'base64').toString(
139
- 'utf8',
140
- );
141
- return compileTemplate(source, vars);
142
- }
143
- }
144
- throw new SkillBundleTemplateNotFoundError(name, uniqueSlugs);
145
- },
146
- };
147
- }