@zhin.js/prompt-section 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 凉菜
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # @zhin.js/prompt-section
2
+
3
+ Generation-owned Agent Prompt Section Feature。插件根目录的
4
+ `agent/prompt-sections/**/*.ts` 默认导出 `defineAgentPromptSection(...)`,并作为
5
+ immutable capability slot 进入当前 generation。
6
+
7
+ Prompt Section 只贡献模型上下文,不授予 Tool、文件、网络、审批或 Workroom 权限。
8
+ `PromptSectionIndex.visible(owner, profile)` 按 Plugin owner 继承链解析,并固定到当前
9
+ generation;HMR 原子发布新 projection,在途 Turn 继续使用旧 snapshot。
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Prompt Section authoring API consumed from `@zhin.js/prompt-section`.
3
+ * @module @zhin.js/prompt-section
4
+ */
5
+ declare const promptSectionBrand: "zhin.agent-prompt-section/1";
6
+ export type PromptSectionLayer = 'system' | 'role' | 'task' | 'context' | 'tools' | 'safety' | 'constraints' | 'examples' | 'memory';
7
+ export type PromptSectionRetention = 'required' | 'preferred' | 'opportunistic';
8
+ export type PromptProfile = 'interactive' | 'schedule';
9
+ export interface AgentPromptSectionDefinition {
10
+ /** @internal Runtime feature brand. */
11
+ readonly $feature: typeof promptSectionBrand;
12
+ readonly title: string;
13
+ readonly content: string;
14
+ readonly layer: PromptSectionLayer;
15
+ readonly order: number;
16
+ readonly retention: PromptSectionRetention;
17
+ readonly maxChars?: number;
18
+ readonly profiles: readonly PromptProfile[];
19
+ readonly platforms?: readonly string[];
20
+ readonly metadata?: Readonly<Record<string, unknown>>;
21
+ }
22
+ export type AgentPromptSectionInput = Omit<AgentPromptSectionDefinition, '$feature' | 'layer' | 'order' | 'retention' | 'profiles'> & Partial<Pick<AgentPromptSectionDefinition, 'layer' | 'order' | 'retention' | 'profiles'>>;
23
+ declare module '@zhin.js/plugin-runtime' {
24
+ interface PluginSetupContext<TConfig = unknown> {
25
+ addPromptSection(localName: string, definition: AgentPromptSectionDefinition): void;
26
+ }
27
+ }
28
+ /**
29
+ * Define a generation-owned Prompt section with deterministic layer and budget policy.
30
+ * Required sections fail closed when they cannot fit the active Prompt budget.
31
+ *
32
+ * @public
33
+ * @experimental
34
+ */
35
+ export declare function defineAgentPromptSection(input: AgentPromptSectionInput): Readonly<AgentPromptSectionDefinition>;
36
+ /** @internal Runtime validation for convention-discovered modules. */
37
+ export declare function parseAgentPromptSectionDefinition(value: unknown): AgentPromptSectionDefinition;
38
+ export {};
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Prompt Section authoring API consumed from `@zhin.js/prompt-section`.
3
+ * @module @zhin.js/prompt-section
4
+ */
5
+ const promptSectionBrand = 'zhin.agent-prompt-section/1';
6
+ /**
7
+ * Define a generation-owned Prompt section with deterministic layer and budget policy.
8
+ * Required sections fail closed when they cannot fit the active Prompt budget.
9
+ *
10
+ * @public
11
+ * @experimental
12
+ */
13
+ export function defineAgentPromptSection(input) {
14
+ if (!input.title?.trim())
15
+ throw new TypeError('Prompt Section title cannot be empty');
16
+ if (!input.content?.trim())
17
+ throw new TypeError('Prompt Section content cannot be empty');
18
+ const layer = input.layer ?? 'context';
19
+ if (!LAYERS.has(layer))
20
+ throw new TypeError(`Invalid Prompt Section layer: ${String(layer)}`);
21
+ const order = input.order ?? 50;
22
+ if (!Number.isSafeInteger(order))
23
+ throw new TypeError('Prompt Section order must be a safe integer');
24
+ const retention = input.retention ?? 'preferred';
25
+ if (!RETENTIONS.has(retention)) {
26
+ throw new TypeError(`Invalid Prompt Section retention: ${String(retention)}`);
27
+ }
28
+ if (input.maxChars !== undefined && (!Number.isSafeInteger(input.maxChars) || input.maxChars <= 0)) {
29
+ throw new TypeError('Prompt Section maxChars must be a positive safe integer');
30
+ }
31
+ const profiles = input.profiles ?? ['interactive'];
32
+ if (!Array.isArray(profiles) || profiles.length === 0 || profiles.some((profile) => !PROFILES.has(profile))) {
33
+ throw new TypeError('Prompt Section profiles must contain interactive or schedule');
34
+ }
35
+ if (new Set(profiles).size !== profiles.length) {
36
+ throw new TypeError('Prompt Section profiles cannot contain duplicates');
37
+ }
38
+ const platforms = input.platforms?.map((platform) => platform.trim());
39
+ if (platforms && (platforms.length === 0
40
+ || platforms.some((platform) => !platform)
41
+ || new Set(platforms).size !== platforms.length)) {
42
+ throw new TypeError('Prompt Section platforms must contain unique non-empty names');
43
+ }
44
+ if (input.metadata !== undefined
45
+ && (!input.metadata || typeof input.metadata !== 'object' || Array.isArray(input.metadata))) {
46
+ throw new TypeError('Prompt Section metadata must be an object');
47
+ }
48
+ return Object.freeze({
49
+ ...input,
50
+ $feature: promptSectionBrand,
51
+ title: input.title.trim(),
52
+ content: input.content.trim(),
53
+ layer,
54
+ order,
55
+ retention,
56
+ profiles: Object.freeze([...profiles]),
57
+ ...(platforms ? { platforms: Object.freeze(platforms) } : {}),
58
+ ...(input.metadata ? { metadata: Object.freeze({ ...input.metadata }) } : {}),
59
+ });
60
+ }
61
+ /** @internal Runtime validation for convention-discovered modules. */
62
+ export function parseAgentPromptSectionDefinition(value) {
63
+ if (!value || typeof value !== 'object')
64
+ throw invalidPromptSection();
65
+ const definition = value;
66
+ if (definition.$feature !== promptSectionBrand
67
+ || typeof definition.title !== 'string'
68
+ || !definition.title.trim()
69
+ || typeof definition.content !== 'string'
70
+ || !definition.content.trim()
71
+ || !LAYERS.has(definition.layer)
72
+ || !Number.isSafeInteger(definition.order)
73
+ || !RETENTIONS.has(definition.retention)
74
+ || (definition.maxChars !== undefined
75
+ && (!Number.isSafeInteger(definition.maxChars) || definition.maxChars <= 0))
76
+ || !Array.isArray(definition.profiles)
77
+ || definition.profiles.length === 0
78
+ || definition.profiles.some((profile) => !PROFILES.has(profile))
79
+ || new Set(definition.profiles).size !== definition.profiles.length
80
+ || (definition.platforms !== undefined
81
+ && (!Array.isArray(definition.platforms)
82
+ || definition.platforms.length === 0
83
+ || definition.platforms.some((platform) => typeof platform !== 'string' || !platform.trim())
84
+ || new Set(definition.platforms).size !== definition.platforms.length))
85
+ || (definition.metadata !== undefined
86
+ && (!definition.metadata || typeof definition.metadata !== 'object' || Array.isArray(definition.metadata))))
87
+ throw invalidPromptSection();
88
+ return defineAgentPromptSection({
89
+ title: definition.title,
90
+ content: definition.content,
91
+ layer: definition.layer,
92
+ order: definition.order,
93
+ retention: definition.retention,
94
+ maxChars: definition.maxChars,
95
+ profiles: definition.profiles,
96
+ platforms: definition.platforms,
97
+ metadata: definition.metadata,
98
+ });
99
+ }
100
+ const LAYERS = new Set([
101
+ 'system', 'role', 'task', 'context', 'tools', 'safety', 'constraints', 'examples', 'memory',
102
+ ]);
103
+ const RETENTIONS = new Set(['required', 'preferred', 'opportunistic']);
104
+ const PROFILES = new Set(['interactive', 'schedule']);
105
+ function invalidPromptSection() {
106
+ return new TypeError('Prompt Section module must default-export defineAgentPromptSection(...)');
107
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Generation-owned Agent Prompt Section authoring contracts.
3
+ * @module @zhin.js/prompt-section
4
+ */
5
+ /** @public Prompt Section authoring contract and `defineAgentPromptSection`. */
6
+ export * from './definition.js';
7
+ /** @internal Runtime Prompt Section projection. */
8
+ export * from './prompt-section-index.js';
9
+ /** @internal Feature provider installed by the Runtime composition root. */
10
+ export * from './provider.js';
11
+ export { default } from './provider.js';
package/lib/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Generation-owned Agent Prompt Section authoring contracts.
3
+ * @module @zhin.js/prompt-section
4
+ */
5
+ /** @public Prompt Section authoring contract and `defineAgentPromptSection`. */
6
+ export * from './definition.js';
7
+ /** @internal Runtime Prompt Section projection. */
8
+ export * from './prompt-section-index.js';
9
+ /** @internal Feature provider installed by the Runtime composition root. */
10
+ export * from './provider.js';
11
+ export { default } from './provider.js';
@@ -0,0 +1,18 @@
1
+ import type { CapabilitySlot, PluginId, RuntimeSnapshot } from '@zhin.js/plugin-runtime';
2
+ import type { AgentPromptSectionDefinition, PromptProfile } from './definition.js';
3
+ export interface PromptSectionDescriptor extends AgentPromptSectionDefinition {
4
+ readonly owner: PluginId;
5
+ readonly name: string;
6
+ readonly qualifiedName: string;
7
+ readonly source: string;
8
+ readonly generation: number;
9
+ }
10
+ export declare class PromptSectionIndex {
11
+ #private;
12
+ private readonly snapshot;
13
+ readonly $projection: "zhin.prompt-section-index/1";
14
+ constructor(slots: readonly Readonly<CapabilitySlot<AgentPromptSectionDefinition>>[], snapshot: RuntimeSnapshot);
15
+ list(): readonly PromptSectionDescriptor[];
16
+ visible(requester: PluginId, profile: PromptProfile): readonly PromptSectionDescriptor[];
17
+ }
18
+ export declare function isPromptSectionIndex(value: unknown): value is PromptSectionIndex;
@@ -0,0 +1,32 @@
1
+ import { OwnerCapabilityIndex, } from '@zhin.js/feature-kit';
2
+ export class PromptSectionIndex {
3
+ snapshot;
4
+ $projection = 'zhin.prompt-section-index/1';
5
+ #index;
6
+ constructor(slots, snapshot) {
7
+ this.snapshot = snapshot;
8
+ this.#index = new OwnerCapabilityIndex(slots, snapshot);
9
+ }
10
+ list() {
11
+ return this.#index.entries().map((entry) => toDescriptor(entry, this.snapshot.generation));
12
+ }
13
+ visible(requester, profile) {
14
+ return Object.freeze(this.#index.visible(requester)
15
+ .filter((entry) => entry.slot.definition.profiles.includes(profile))
16
+ .map((entry) => toDescriptor(entry, this.snapshot.generation)));
17
+ }
18
+ }
19
+ export function isPromptSectionIndex(value) {
20
+ return !!value && typeof value === 'object'
21
+ && value.$projection === 'zhin.prompt-section-index/1';
22
+ }
23
+ function toDescriptor(entry, generation) {
24
+ return Object.freeze({
25
+ ...entry.slot.definition,
26
+ owner: entry.owner,
27
+ name: entry.name,
28
+ qualifiedName: entry.qualifiedName,
29
+ source: entry.source,
30
+ generation,
31
+ });
32
+ }
@@ -0,0 +1,5 @@
1
+ import { PromptSectionIndex } from './prompt-section-index.js';
2
+ export declare const promptSectionFeatureId: import("@zhin.js/plugin-runtime").FeatureId;
3
+ declare const promptSectionFeature: Readonly<import("@zhin.js/feature-kit").FeatureProvider<import("./definition.js").AgentPromptSectionDefinition, PromptSectionIndex>>;
4
+ export { promptSectionFeature };
5
+ export default promptSectionFeature;
@@ -0,0 +1,25 @@
1
+ import { featureId } from '@zhin.js/plugin-runtime';
2
+ import { defineFeatureProvider, typeScriptModules } from '@zhin.js/feature-kit';
3
+ import { parseAgentPromptSectionDefinition } from './definition.js';
4
+ import { PromptSectionIndex } from './prompt-section-index.js';
5
+ export const promptSectionFeatureId = featureId('zhin.agent-prompt-section');
6
+ const promptSectionFeature = defineFeatureProvider({
7
+ protocol: 1,
8
+ id: promptSectionFeatureId,
9
+ authoring: {
10
+ setupMethod: 'addPromptSection',
11
+ conventions: [typeScriptModules({
12
+ id: 'agent-prompt-sections-ts',
13
+ directory: 'agent/prompt-sections',
14
+ recursive: true,
15
+ })],
16
+ validate: parseAgentPromptSectionDefinition,
17
+ },
18
+ runtime: {
19
+ project(slots, context) {
20
+ return { value: new PromptSectionIndex(slots, context.snapshot) };
21
+ },
22
+ },
23
+ });
24
+ export { promptSectionFeature };
25
+ export default promptSectionFeature;
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@zhin.js/prompt-section",
3
+ "version": "0.0.0",
4
+ "description": "Generation-owned Agent Prompt Section Feature for Zhin Plugin Runtime",
5
+ "type": "module",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "development": "./src/index.ts",
12
+ "import": "./lib/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "lib",
17
+ "src"
18
+ ],
19
+ "dependencies": {
20
+ "@zhin.js/feature-kit": "1.0.12",
21
+ "@zhin.js/plugin-runtime": "1.1.7"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^26.1.2",
25
+ "typescript": "^6.0.3"
26
+ },
27
+ "zhin": {
28
+ "protocol": 1,
29
+ "type": "feature",
30
+ "entry": "./lib/provider.js",
31
+ "engine": "^1.0.0",
32
+ "featureApi": "1.0.0"
33
+ },
34
+ "engines": {
35
+ "node": "^20.19.0 || >=22.12.0"
36
+ },
37
+ "license": "MIT",
38
+ "private": false,
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/zhinjs/zhin.git",
42
+ "directory": "packages/im/prompt-section"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "registry": "https://registry.npmjs.org"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc",
50
+ "clean": "rimraf lib",
51
+ "test": "vitest run --root ../../.. packages/im/prompt-section/tests"
52
+ }
53
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Prompt Section authoring API consumed from `@zhin.js/prompt-section`.
3
+ * @module @zhin.js/prompt-section
4
+ */
5
+ const promptSectionBrand = 'zhin.agent-prompt-section/1' as const;
6
+
7
+ export type PromptSectionLayer =
8
+ | 'system'
9
+ | 'role'
10
+ | 'task'
11
+ | 'context'
12
+ | 'tools'
13
+ | 'safety'
14
+ | 'constraints'
15
+ | 'examples'
16
+ | 'memory';
17
+
18
+ export type PromptSectionRetention = 'required' | 'preferred' | 'opportunistic';
19
+ export type PromptProfile = 'interactive' | 'schedule';
20
+
21
+ export interface AgentPromptSectionDefinition {
22
+ /** @internal Runtime feature brand. */
23
+ readonly $feature: typeof promptSectionBrand;
24
+ readonly title: string;
25
+ readonly content: string;
26
+ readonly layer: PromptSectionLayer;
27
+ readonly order: number;
28
+ readonly retention: PromptSectionRetention;
29
+ readonly maxChars?: number;
30
+ readonly profiles: readonly PromptProfile[];
31
+ readonly platforms?: readonly string[];
32
+ readonly metadata?: Readonly<Record<string, unknown>>;
33
+ }
34
+
35
+ export type AgentPromptSectionInput = Omit<
36
+ AgentPromptSectionDefinition,
37
+ '$feature' | 'layer' | 'order' | 'retention' | 'profiles'
38
+ > & Partial<Pick<
39
+ AgentPromptSectionDefinition,
40
+ 'layer' | 'order' | 'retention' | 'profiles'
41
+ >>;
42
+
43
+ declare module '@zhin.js/plugin-runtime' {
44
+ // Type parameter name must match the base PluginSetupContext declaration (TS2428).
45
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
46
+ interface PluginSetupContext<TConfig = unknown> {
47
+ addPromptSection(localName: string, definition: AgentPromptSectionDefinition): void;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Define a generation-owned Prompt section with deterministic layer and budget policy.
53
+ * Required sections fail closed when they cannot fit the active Prompt budget.
54
+ *
55
+ * @public
56
+ * @experimental
57
+ */
58
+ export function defineAgentPromptSection(
59
+ input: AgentPromptSectionInput,
60
+ ): Readonly<AgentPromptSectionDefinition> {
61
+ if (!input.title?.trim()) throw new TypeError('Prompt Section title cannot be empty');
62
+ if (!input.content?.trim()) throw new TypeError('Prompt Section content cannot be empty');
63
+ const layer = input.layer ?? 'context';
64
+ if (!LAYERS.has(layer)) throw new TypeError(`Invalid Prompt Section layer: ${String(layer)}`);
65
+ const order = input.order ?? 50;
66
+ if (!Number.isSafeInteger(order)) throw new TypeError('Prompt Section order must be a safe integer');
67
+ const retention = input.retention ?? 'preferred';
68
+ if (!RETENTIONS.has(retention)) {
69
+ throw new TypeError(`Invalid Prompt Section retention: ${String(retention)}`);
70
+ }
71
+ if (input.maxChars !== undefined && (!Number.isSafeInteger(input.maxChars) || input.maxChars <= 0)) {
72
+ throw new TypeError('Prompt Section maxChars must be a positive safe integer');
73
+ }
74
+ const profiles = input.profiles ?? ['interactive'];
75
+ if (!Array.isArray(profiles) || profiles.length === 0 || profiles.some((profile) => !PROFILES.has(profile))) {
76
+ throw new TypeError('Prompt Section profiles must contain interactive or schedule');
77
+ }
78
+ if (new Set(profiles).size !== profiles.length) {
79
+ throw new TypeError('Prompt Section profiles cannot contain duplicates');
80
+ }
81
+ const platforms = input.platforms?.map((platform) => platform.trim());
82
+ if (platforms && (platforms.length === 0
83
+ || platforms.some((platform) => !platform)
84
+ || new Set(platforms).size !== platforms.length)) {
85
+ throw new TypeError('Prompt Section platforms must contain unique non-empty names');
86
+ }
87
+ if (input.metadata !== undefined
88
+ && (!input.metadata || typeof input.metadata !== 'object' || Array.isArray(input.metadata))) {
89
+ throw new TypeError('Prompt Section metadata must be an object');
90
+ }
91
+ return Object.freeze({
92
+ ...input,
93
+ $feature: promptSectionBrand,
94
+ title: input.title.trim(),
95
+ content: input.content.trim(),
96
+ layer,
97
+ order,
98
+ retention,
99
+ profiles: Object.freeze([...profiles]),
100
+ ...(platforms ? { platforms: Object.freeze(platforms) } : {}),
101
+ ...(input.metadata ? { metadata: Object.freeze({ ...input.metadata }) } : {}),
102
+ });
103
+ }
104
+
105
+ /** @internal Runtime validation for convention-discovered modules. */
106
+ export function parseAgentPromptSectionDefinition(value: unknown): AgentPromptSectionDefinition {
107
+ if (!value || typeof value !== 'object') throw invalidPromptSection();
108
+ const definition = value as Partial<AgentPromptSectionDefinition>;
109
+ if (
110
+ definition.$feature !== promptSectionBrand
111
+ || typeof definition.title !== 'string'
112
+ || !definition.title.trim()
113
+ || typeof definition.content !== 'string'
114
+ || !definition.content.trim()
115
+ || !LAYERS.has(definition.layer as PromptSectionLayer)
116
+ || !Number.isSafeInteger(definition.order)
117
+ || !RETENTIONS.has(definition.retention as PromptSectionRetention)
118
+ || (definition.maxChars !== undefined
119
+ && (!Number.isSafeInteger(definition.maxChars) || definition.maxChars <= 0))
120
+ || !Array.isArray(definition.profiles)
121
+ || definition.profiles.length === 0
122
+ || definition.profiles.some((profile) => !PROFILES.has(profile))
123
+ || new Set(definition.profiles).size !== definition.profiles.length
124
+ || (definition.platforms !== undefined
125
+ && (!Array.isArray(definition.platforms)
126
+ || definition.platforms.length === 0
127
+ || definition.platforms.some((platform) => typeof platform !== 'string' || !platform.trim())
128
+ || new Set(definition.platforms).size !== definition.platforms.length))
129
+ || (definition.metadata !== undefined
130
+ && (!definition.metadata || typeof definition.metadata !== 'object' || Array.isArray(definition.metadata)))
131
+ ) throw invalidPromptSection();
132
+ return defineAgentPromptSection({
133
+ title: definition.title,
134
+ content: definition.content,
135
+ layer: definition.layer,
136
+ order: definition.order,
137
+ retention: definition.retention,
138
+ maxChars: definition.maxChars,
139
+ profiles: definition.profiles,
140
+ platforms: definition.platforms,
141
+ metadata: definition.metadata,
142
+ });
143
+ }
144
+
145
+ const LAYERS = new Set<PromptSectionLayer>([
146
+ 'system', 'role', 'task', 'context', 'tools', 'safety', 'constraints', 'examples', 'memory',
147
+ ]);
148
+ const RETENTIONS = new Set<PromptSectionRetention>(['required', 'preferred', 'opportunistic']);
149
+ const PROFILES = new Set<PromptProfile>(['interactive', 'schedule']);
150
+
151
+ function invalidPromptSection(): TypeError {
152
+ return new TypeError('Prompt Section module must default-export defineAgentPromptSection(...)');
153
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Generation-owned Agent Prompt Section authoring contracts.
3
+ * @module @zhin.js/prompt-section
4
+ */
5
+ /** @public Prompt Section authoring contract and `defineAgentPromptSection`. */
6
+ export * from './definition.js';
7
+ /** @internal Runtime Prompt Section projection. */
8
+ export * from './prompt-section-index.js';
9
+ /** @internal Feature provider installed by the Runtime composition root. */
10
+ export * from './provider.js';
11
+ export { default } from './provider.js';
@@ -0,0 +1,58 @@
1
+ import type { CapabilitySlot, PluginId, RuntimeSnapshot } from '@zhin.js/plugin-runtime';
2
+ import {
3
+ OwnerCapabilityIndex,
4
+ type OwnerCapabilityEntry,
5
+ } from '@zhin.js/feature-kit';
6
+ import type {
7
+ AgentPromptSectionDefinition,
8
+ PromptProfile,
9
+ } from './definition.js';
10
+
11
+ export interface PromptSectionDescriptor extends AgentPromptSectionDefinition {
12
+ readonly owner: PluginId;
13
+ readonly name: string;
14
+ readonly qualifiedName: string;
15
+ readonly source: string;
16
+ readonly generation: number;
17
+ }
18
+
19
+ export class PromptSectionIndex {
20
+ readonly $projection = 'zhin.prompt-section-index/1' as const;
21
+ readonly #index: OwnerCapabilityIndex<AgentPromptSectionDefinition>;
22
+
23
+ constructor(
24
+ slots: readonly Readonly<CapabilitySlot<AgentPromptSectionDefinition>>[],
25
+ private readonly snapshot: RuntimeSnapshot,
26
+ ) {
27
+ this.#index = new OwnerCapabilityIndex(slots, snapshot);
28
+ }
29
+
30
+ list(): readonly PromptSectionDescriptor[] {
31
+ return this.#index.entries().map((entry) => toDescriptor(entry, this.snapshot.generation));
32
+ }
33
+
34
+ visible(requester: PluginId, profile: PromptProfile): readonly PromptSectionDescriptor[] {
35
+ return Object.freeze(this.#index.visible(requester)
36
+ .filter((entry) => entry.slot.definition.profiles.includes(profile))
37
+ .map((entry) => toDescriptor(entry, this.snapshot.generation)));
38
+ }
39
+ }
40
+
41
+ export function isPromptSectionIndex(value: unknown): value is PromptSectionIndex {
42
+ return !!value && typeof value === 'object'
43
+ && (value as { readonly $projection?: unknown }).$projection === 'zhin.prompt-section-index/1';
44
+ }
45
+
46
+ function toDescriptor(
47
+ entry: OwnerCapabilityEntry<AgentPromptSectionDefinition>,
48
+ generation: number,
49
+ ): PromptSectionDescriptor {
50
+ return Object.freeze({
51
+ ...entry.slot.definition,
52
+ owner: entry.owner,
53
+ name: entry.name,
54
+ qualifiedName: entry.qualifiedName,
55
+ source: entry.source,
56
+ generation,
57
+ });
58
+ }
@@ -0,0 +1,28 @@
1
+ import { featureId } from '@zhin.js/plugin-runtime';
2
+ import { defineFeatureProvider, typeScriptModules } from '@zhin.js/feature-kit';
3
+ import { parseAgentPromptSectionDefinition } from './definition.js';
4
+ import { PromptSectionIndex } from './prompt-section-index.js';
5
+
6
+ export const promptSectionFeatureId = featureId('zhin.agent-prompt-section');
7
+
8
+ const promptSectionFeature = defineFeatureProvider({
9
+ protocol: 1,
10
+ id: promptSectionFeatureId,
11
+ authoring: {
12
+ setupMethod: 'addPromptSection',
13
+ conventions: [typeScriptModules({
14
+ id: 'agent-prompt-sections-ts',
15
+ directory: 'agent/prompt-sections',
16
+ recursive: true,
17
+ })],
18
+ validate: parseAgentPromptSectionDefinition,
19
+ },
20
+ runtime: {
21
+ project(slots, context) {
22
+ return { value: new PromptSectionIndex(slots, context.snapshot) };
23
+ },
24
+ },
25
+ });
26
+
27
+ export { promptSectionFeature };
28
+ export default promptSectionFeature;