@onco-foundry/agent-template 0.1.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.
@@ -0,0 +1,112 @@
1
+ import { type AgentSpec, type ModelClient } from 'agent-lattice';
2
+ import { z } from 'zod';
3
+ import { type Capability } from '@onco-foundry/capability-registry';
4
+ import type { CapabilityDelegation } from '@onco-foundry/agent-runtime';
5
+ import { type Tracer } from '@onco-foundry/trace-port';
6
+ /**
7
+ * 版本化 prompt 资源的 manifest 形状:结构版本号与内容版本号分开,
8
+ * systemPrompt 是指向版本目录内文件的引用(含 sha256,加载时校验完整性)。
9
+ * 模板侧创建版本目录与加载生效版本共用这一个 schema。
10
+ */
11
+ export declare const promptManifestSchema: z.ZodObject<{
12
+ schemaVersion: z.ZodString;
13
+ promptVersion: z.ZodString;
14
+ provenance: z.ZodString;
15
+ systemPrompt: z.ZodObject<{
16
+ file: z.ZodString;
17
+ sha256: z.ZodString;
18
+ }, z.core.$strip>;
19
+ }, z.core.$strip>;
20
+ /**
21
+ * 思考预算钳制:思考与工具调用共享 maxTokens 输出预算,
22
+ * budgetTokens 必须小于 maxTokens,否则 API 直接报错。maxTokens 至少为 2。
23
+ */
24
+ export declare const clampThinkingBudgetTokens: (requestedBudgetTokens: number, maxTokens: number) => number;
25
+ /** 能力名片:名字、种类、一句话职责、输入输出契约。版本不在名片上——版本归场景(ADR-10),由 createCapability 落定。 */
26
+ export type AgentTemplateCard<I = unknown, O = unknown> = {
27
+ readonly name: string;
28
+ readonly kind: 'agent';
29
+ readonly summary: string;
30
+ readonly input: z.ZodType<I>;
31
+ readonly output: z.ZodType<O>;
32
+ };
33
+ export type AgentTemplateDeclaration<I, O> = {
34
+ /** kebab-case:能力名片名;spec 名由它派生(kebab→snake,id.replaceAll('-', '_'))。 */
35
+ id: string;
36
+ /** 一句话职责:名片 summary,也是 typed 工具菜单文案的缺省。 */
37
+ summary: string;
38
+ /** 输入契约(zod)。 */
39
+ input: z.ZodType<I>;
40
+ /** submit 交付契约(zod):名片 output = spec 的 outputSchema(SDK 据此注入 submit_output)。 */
41
+ output: z.ZodType<O>;
42
+ /**
43
+ * mapInput 话术:把校验后的 typed 入参投影成子级 prompt。sync——需要
44
+ * per-call 异步预处理(取图、缩放)的模板不适用本声明件,维持自建工厂。
45
+ */
46
+ task: (input: I) => string;
47
+ /**
48
+ * 版本化 prompt 资源根(含 current.json 指针):
49
+ * new URL('./resources/prompts/', import.meta.url)。生效版本解析归模板,编排方零感知。
50
+ */
51
+ promptDir: URL;
52
+ /**
53
+ * 可选限额。缺省:maxTokens 16384、maxTurns 10、thinking 关闭;
54
+ * thinkingBudgetTokens 给了才开 thinking(按 clampThinkingBudgetTokens 钳制到 maxTokens 以内)。
55
+ */
56
+ limits?: {
57
+ maxTokens?: number;
58
+ maxTurns?: number;
59
+ thinkingBudgetTokens?: number;
60
+ };
61
+ };
62
+ export type CreateTemplateAgentOptions = {
63
+ model: {
64
+ model: string;
65
+ baseURL?: string;
66
+ apiKey?: string;
67
+ };
68
+ /** 测试注入缝:替换真实模型客户端,不碰网络。 */
69
+ modelClient?: ModelClient;
70
+ /** 缺省 noop tracer;prompt 版本加载后 setVersions({ prompt }) 回填。 */
71
+ tracer?: Tracer;
72
+ /** prompt 版本覆盖缝:指定版本目录名则跳过 current.json 指针,试跑/对照工具用。 */
73
+ promptVersion?: string;
74
+ };
75
+ export type AgentTemplate<I, O> = {
76
+ /** 能力名片:{ name: id, kind: 'agent', summary, input, output },无 version(版本归场景,ADR-10)。 */
77
+ readonly card: AgentTemplateCard<I, O>;
78
+ /**
79
+ * 加载生效版本 prompt(或 promptVersion 指定版本):返回 { systemPrompt, promptVersion }。
80
+ * 资源缺文件当场抛错。
81
+ */
82
+ loadPrompt(options?: {
83
+ promptVersion?: string;
84
+ }): Promise<{
85
+ systemPrompt: string;
86
+ promptVersion: string;
87
+ }>;
88
+ /** 构建 AgentSpec:加载 prompt + defineAgent(裸会话 workspace:false,outputSchema 交给 SDK 注入 submit_output)。 */
89
+ createSpec(options: CreateTemplateAgentOptions): Promise<AgentSpec>;
90
+ /** typed 委派两块料:{ spec, mapInput: task }。async——prompt 加载是 IO。 */
91
+ createDelegation(options: CreateTemplateAgentOptions): Promise<CapabilityDelegation>;
92
+ /**
93
+ * 完整能力:defineCapability({ ...card, version: version ?? promptVersion, run })。
94
+ * run 由库提供:parse 入参 → spec.spawn().prompt(task(input)) → is_error 抛错
95
+ * → structuredResult 缺失抛错 → output.parse 后返回。
96
+ */
97
+ createCapability(options: CreateTemplateAgentOptions & {
98
+ version?: string;
99
+ }): Promise<Capability<I, O>>;
100
+ };
101
+ /**
102
+ * 智能体模板声明件:同构简单模板(submit 交付过 schema 即可、无工具、无 loop 外组装)
103
+ * 的生产侧形状。一次声明吐出四个出口:名片 / loadPrompt / spec / delegation / capability。
104
+ *
105
+ * 版本绑定口径:声明件模板的交付 payload = 纯业务契约,版本绑定不进 payload——
106
+ * SDK submit_output 形态下模型交不出版本字段,且 agentTool 要求 outputSchema 与
107
+ * target 声明一致。版本链走三处:capability.version(缺省 promptVersion)、
108
+ * ToolDefinition.metadata(createTypedAgentTool 投射时写入)、createCapability
109
+ * 返回能力的 describe()。这与 knowledge-gatekeeper(自定义 submit 工具把版本注入
110
+ * payload)是两派实现,不要混用。
111
+ */
112
+ export declare const defineAgentTemplate: <I, O>(declaration: AgentTemplateDeclaration<I, O>) => AgentTemplate<I, O>;
@@ -0,0 +1,126 @@
1
+ import { defineAgent } from 'agent-lattice';
2
+ import { z } from 'zod';
3
+ import { defineCapability } from '@onco-foundry/capability-registry';
4
+ import { loadActiveVersionedResource, resourceFileReferenceSchema, versionedManifestBaseShape, } from '@onco-foundry/resource-versioning';
5
+ import { createTracer } from '@onco-foundry/trace-port';
6
+ import { AppError } from '@onco-foundry/errors';
7
+ /**
8
+ * 版本化 prompt 资源的 manifest 形状:结构版本号与内容版本号分开,
9
+ * systemPrompt 是指向版本目录内文件的引用(含 sha256,加载时校验完整性)。
10
+ * 模板侧创建版本目录与加载生效版本共用这一个 schema。
11
+ */
12
+ export const promptManifestSchema = z.object({
13
+ ...versionedManifestBaseShape,
14
+ promptVersion: z.string().min(1),
15
+ provenance: z.string().min(1),
16
+ systemPrompt: resourceFileReferenceSchema,
17
+ });
18
+ /** 缺省输出预算:无工具的问答/判定类交付,16k 足够。 */
19
+ const DEFAULT_MAX_TOKENS = 16_384;
20
+ /** 缺省轮次上限:无工具模板一次 loop 典型路径是读入即交付。 */
21
+ const DEFAULT_MAX_TURNS = 10;
22
+ /**
23
+ * 思考预算钳制:思考与工具调用共享 maxTokens 输出预算,
24
+ * budgetTokens 必须小于 maxTokens,否则 API 直接报错。maxTokens 至少为 2。
25
+ */
26
+ export const clampThinkingBudgetTokens = (requestedBudgetTokens, maxTokens) => Math.min(requestedBudgetTokens, Math.max(maxTokens, 2) - 1);
27
+ const kebabCasePattern = /^[a-z0-9]+(-[a-z0-9]+)*$/;
28
+ /**
29
+ * 智能体模板声明件:同构简单模板(submit 交付过 schema 即可、无工具、无 loop 外组装)
30
+ * 的生产侧形状。一次声明吐出四个出口:名片 / loadPrompt / spec / delegation / capability。
31
+ *
32
+ * 版本绑定口径:声明件模板的交付 payload = 纯业务契约,版本绑定不进 payload——
33
+ * SDK submit_output 形态下模型交不出版本字段,且 agentTool 要求 outputSchema 与
34
+ * target 声明一致。版本链走三处:capability.version(缺省 promptVersion)、
35
+ * ToolDefinition.metadata(createTypedAgentTool 投射时写入)、createCapability
36
+ * 返回能力的 describe()。这与 knowledge-gatekeeper(自定义 submit 工具把版本注入
37
+ * payload)是两派实现,不要混用。
38
+ */
39
+ export const defineAgentTemplate = (declaration) => {
40
+ if (!kebabCasePattern.test(declaration.id)) {
41
+ throw new AppError(`模板 id 必须是 kebab-case(小写字母数字与连字符):${declaration.id}`);
42
+ }
43
+ const { id } = declaration;
44
+ const card = {
45
+ name: id,
46
+ kind: 'agent',
47
+ summary: declaration.summary,
48
+ input: declaration.input,
49
+ output: declaration.output,
50
+ };
51
+ const loadPrompt = async (loadOptions) => {
52
+ const promptResource = await loadActiveVersionedResource({
53
+ baseDir: declaration.promptDir,
54
+ manifestSchema: promptManifestSchema,
55
+ ...(loadOptions?.promptVersion !== undefined
56
+ ? { versionOverride: loadOptions.promptVersion }
57
+ : {}),
58
+ });
59
+ const systemPrompt = promptResource.files.get(promptResource.manifest.systemPrompt.file);
60
+ if (systemPrompt === undefined) {
61
+ throw new Error(`模板 ${id} 的 prompt 资源缺少文件:${promptResource.manifest.systemPrompt.file}`);
62
+ }
63
+ return { systemPrompt, promptVersion: promptResource.manifest.promptVersion };
64
+ };
65
+ /** 四个出口共用同一份 spec 构建:prompt 加载、限额、tracer 回填完全一致。 */
66
+ const buildSpec = async (options) => {
67
+ const { systemPrompt, promptVersion } = await loadPrompt(options.promptVersion === undefined ? undefined : { promptVersion: options.promptVersion });
68
+ // 调用方不传 tracer 时用 noop:追踪摘掉后模板照常运行。
69
+ const tracer = options.tracer ?? createTracer({ kind: 'noop' });
70
+ // prompt 版本在装配处还不知道,加载完版本化资源后回填进版本链。
71
+ tracer.setVersions({ prompt: promptVersion });
72
+ const maxTokens = declaration.limits?.maxTokens ?? DEFAULT_MAX_TOKENS;
73
+ const maxTurns = declaration.limits?.maxTurns ?? DEFAULT_MAX_TURNS;
74
+ const thinkingBudgetTokens = declaration.limits?.thinkingBudgetTokens;
75
+ // workspace: false = 裸会话:不装内建工作区工具,同构简单模板不需要文件/Bash 权限面。
76
+ // spec 每次委派生成全新会话,历史不互串、并发不互踩。
77
+ const spec = defineAgent({
78
+ name: id.replaceAll('-', '_'),
79
+ model: options.model.model,
80
+ baseURL: options.model.baseURL,
81
+ apiKey: options.model.apiKey,
82
+ modelClient: options.modelClient,
83
+ systemPrompt,
84
+ maxTokens,
85
+ maxTurns,
86
+ thinkingConfig: thinkingBudgetTokens === undefined
87
+ ? { type: 'disabled' }
88
+ : { type: 'enabled', budgetTokens: clampThinkingBudgetTokens(thinkingBudgetTokens, maxTokens) },
89
+ // 无领域校验要过,交付契约直接交给 SDK:声明 outputSchema 后 SDK 注入
90
+ // submit_output 工具,没提交就收尾会以 error_missing_output 失败。
91
+ outputSchema: declaration.output,
92
+ tracer,
93
+ workspace: false,
94
+ });
95
+ return { spec, promptVersion };
96
+ };
97
+ return {
98
+ card,
99
+ loadPrompt,
100
+ createSpec: async (options) => (await buildSpec(options)).spec,
101
+ createDelegation: async (options) => {
102
+ const { spec } = await buildSpec(options);
103
+ return { spec, mapInput: (input) => declaration.task(input) };
104
+ },
105
+ createCapability: async (options) => {
106
+ const { spec, promptVersion } = await buildSpec(options);
107
+ const run = async (rawInput) => {
108
+ // 运行期边界:typed 参数挡不住 any 与强转,这次 parse 是真实校验,不可删。
109
+ const input = declaration.input.parse(rawInput);
110
+ const response = await spec.spawn().prompt(declaration.task(input));
111
+ if (response.is_error) {
112
+ throw response.error ?? new Error(`模板 ${id} 运行失败:${response.subtype}`);
113
+ }
114
+ if (response.structuredResult === undefined) {
115
+ throw new Error(`模板 ${id} 的模型未提交结构化交付,本次运行不算完成`);
116
+ }
117
+ return declaration.output.parse(response.structuredResult);
118
+ };
119
+ return defineCapability({
120
+ ...card,
121
+ version: options.version ?? promptVersion,
122
+ run,
123
+ });
124
+ },
125
+ };
126
+ };
@@ -0,0 +1,2 @@
1
+ export { clampThinkingBudgetTokens, defineAgentTemplate, promptManifestSchema, type AgentTemplate, type AgentTemplateCard, type AgentTemplateDeclaration, type CreateTemplateAgentOptions, } from './agent_template.ts';
2
+ export type { CapabilityDelegation } from '@onco-foundry/agent-runtime';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { clampThinkingBudgetTokens, defineAgentTemplate, promptManifestSchema, } from './agent_template.js';
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@onco-foundry/agent-template",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "agent-lattice": "0.23.0",
16
+ "zod": "^4.4.3",
17
+ "@onco-foundry/errors": "0.1.1",
18
+ "@onco-foundry/capability-registry": "0.1.1",
19
+ "@onco-foundry/resource-versioning": "0.1.1",
20
+ "@onco-foundry/agent-runtime": "0.2.0",
21
+ "@onco-foundry/trace-port": "0.3.0"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.build.json"
28
+ },
29
+ "types": "./dist/index.d.ts"
30
+ }