@domesystems/templates 0.4.0 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domesystems/templates",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Pull, publish, and run versioned Dome templates.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/generate.mjs CHANGED
@@ -64,6 +64,29 @@ function quotaBlocks(quotas, agents) {
64
64
  });
65
65
  }
66
66
 
67
+ function managedModelReference(manifest, name) {
68
+ if (manifest.pools.some((pool) => pool.name === name)) return `dome_llm_pool.${label(name)}.name`;
69
+ if (manifest.models.some((model) => model.name === name)) return `dome_llm_connection.${label(name)}.name`;
70
+ throw new Error(`Managed agent default_model ${name} must name a pool or model.`);
71
+ }
72
+
73
+ function triggerBlocks(triggers) {
74
+ return triggers.map((trigger) => {
75
+ const kind = required(trigger, "kind", `Trigger ${trigger.name} needs kind.`);
76
+ if (!["schedule", "webhook"].includes(kind)) throw new Error(`Trigger ${trigger.name} has unsupported kind ${kind}.`);
77
+ if (kind === "schedule" && !trigger.cron) throw new Error(`Schedule trigger ${trigger.name} needs cron.`);
78
+ const lines = [attr("workspace_id", "var.workspace_id"), attr("name", q(required(trigger, "name", "Every trigger needs a name."))), ...(trigger.description ? [attr("description", q(trigger.description))] : []), attr("kind", q(kind))];
79
+ for (const key of ["enabled", "cron", "timezone", "input", "max_concurrent_runs", "catch_up", "catch_up_deadline_seconds", "max_retries"]) if (trigger[key] !== undefined) lines.push(attr(key, typeof trigger[key] === "string" ? q(trigger[key]) : String(trigger[key])));
80
+ const targets = trigger.targets ?? [];
81
+ if (!Array.isArray(targets) || !targets.length) throw new Error(`Trigger ${trigger.name} needs at least one target.`);
82
+ lines.push(`targets = [${targets.map((target) => {
83
+ if (target?.kind !== "managed_agent" || typeof target.name !== "string") throw new Error(`Trigger ${trigger.name} targets must name a managed_agent.`);
84
+ return `{ kind = "managed_agent", name = dome_managed_agent.${label(target.name)}.name${target.disabled === undefined ? "" : `, disabled = ${Boolean(target.disabled)}`} }`;
85
+ }).join(", ")}]`);
86
+ return block("dome_trigger", label(trigger.name), lines);
87
+ });
88
+ }
89
+
67
90
  export function renderDomeTerraform(manifest) {
68
91
  if (!manifest.gateways.length) throw new Error("template.yaml must declare at least one gateway.");
69
92
  const blocks = [];
@@ -94,7 +117,8 @@ export function renderDomeTerraform(manifest) {
94
117
  }
95
118
  for (const agent of manifest.agents) {
96
119
  const agentLabel = label(agent.name); const managed = agent.type === "managed"; const resourceType = managed ? "dome_managed_agent" : "dome_agent";
97
- const lines = [attr("workspace_id", "var.workspace_id"), attr("name", q(agent.name)), attr("allowed_gateways", `[${(agent.allowed_gateways ?? []).map((gateway) => `dome_gateway.${label(gateway)}.name`).join(", ")}]`)];
120
+ const lines = [attr("workspace_id", "var.workspace_id"), attr("name", q(agent.name))];
121
+ if (!managed) lines.push(attr("allowed_gateways", `[${(agent.allowed_gateways ?? []).map((gateway) => `dome_gateway.${label(gateway)}.name`).join(", ")}]`));
98
122
  if (!managed && agent.act_as) {
99
123
  const { method, required: actAsRequired, hmac_secret: hmacSecret, allowed_subjects: allowedSubjects } = agent.act_as;
100
124
  if (!method) throw new Error(`Agent ${agent.name} act_as needs method.`);
@@ -103,15 +127,13 @@ export function renderDomeTerraform(manifest) {
103
127
  if (allowedSubjects) lines.push(attr("actas_allowed_subjects", `[${allowedSubjects.map(q).join(", ")}]`));
104
128
  }
105
129
  if (managed) {
106
- if (!agent.system_prompt?.path || !agent.default_model) throw new Error(`Managed agent ${agent.name} needs system_prompt.path and default_model.`);
107
- lines.push(attr("system_prompt", `file("${'${path.module}'}/${agent.system_prompt.path}")`), attr("default_model", `dome_llm_pool.${label(agent.default_model)}.name`));
108
- const trigger = agent.trigger ?? {}; const config = { ...(trigger.manual === undefined ? {} : { manual: { enabled: Boolean(trigger.manual) } }), ...(trigger.webhook === undefined ? {} : { webhook: { enabled: Boolean(trigger.webhook) } }), ...(trigger.schedule ? { schedule: trigger.schedule } : {}) };
109
- if (Object.keys(config).length) lines.push(attr("trigger_config", `jsonencode(${JSON.stringify(config)})`));
130
+ if (!agent.system_prompt?.content || !agent.default_model) throw new Error(`Managed agent ${agent.name} needs system_prompt and default_model.`);
131
+ lines.push(attr("system_prompt", "<<-PROMPT"), ...agent.system_prompt.content.split("\n").map((line) => line.trimEnd()), "PROMPT", attr("default_model", managedModelReference(manifest, agent.default_model)), attr("gateway", `dome_gateway.${label(agent.gateway)}.name`));
110
132
  }
111
133
  blocks.push(block(resourceType, agentLabel, lines), ...rulesBlock(agent, resourceType, agentLabel));
112
134
  if (!managed) for (const key of agent.keys ?? []) blocks.push(block("dome_agent_key", `${agentLabel}_${label(required(key, "name", `Agent ${agent.name} keys need a name.`))}`, [attr("workspace_id", "var.workspace_id"), attr("agent", `dome_agent.${agentLabel}.name`), attr("name", q(key.name))]));
113
135
  }
114
- blocks.push(...filterBlocks(manifest.filters), ...quotaBlocks(manifest.quotas, new Map(manifest.agents.map((agent) => [agent.name, agent.type]))));
136
+ blocks.push(...filterBlocks(manifest.filters), ...quotaBlocks(manifest.quotas, new Map(manifest.agents.map((agent) => [agent.name, agent.type]))), ...triggerBlocks(manifest.triggers));
115
137
  const header = `# Generated by @domesystems/templates from template.yaml. Do not edit.\nterraform {\n required_providers {\n dome = { source = ${q("dome-systems/dome")}, version = ${q(">= 0.1.0")} }\n }\n}\n\nvariable "workspace_id" { type = string }`;
116
138
  const outputs = manifest.agents.filter((agent) => agent.type === "external").flatMap((agent) => (agent.keys ?? []).map((key) => {
117
139
  const agentLabel = label(agent.name); const keyLabel = label(key.name);
package/src/manifest.mjs CHANGED
@@ -67,6 +67,18 @@ function normalizeRuleFiles(root, agent, index) {
67
67
  return { ...agent, rules: { ...agent.rules, files: normalized } };
68
68
  }
69
69
 
70
+ function normalizeManagedAgent(root, agent, index) {
71
+ if (agent.type !== "managed") return agent;
72
+ const prompt = agent.system_prompt;
73
+ if (!prompt || typeof prompt !== "object" || Array.isArray(prompt)) throw new Error(`agents[${index}].system_prompt must declare path or inline.`);
74
+ const hasPath = typeof prompt.path === "string";
75
+ const hasInline = typeof prompt.inline === "string";
76
+ if (hasPath === hasInline) throw new Error(`agents[${index}].system_prompt must declare exactly one of path or inline.`);
77
+ if (typeof agent.gateway !== "string" || !agent.gateway.trim()) throw new Error(`Managed agent ${agent.name} needs gateway.`);
78
+ if (agent.allowed_gateways !== undefined || agent.trigger !== undefined) throw new Error(`Managed agent ${agent.name} uses gateway and top-level triggers; allowed_gateways and trigger are not supported.`);
79
+ return { ...agent, system_prompt: { content: hasPath ? fs.readFileSync(sourcePath(root, prompt.path, `agents[${index}].system_prompt`), "utf8") : prompt.inline, source: hasPath ? prompt.path : "inline" } };
80
+ }
81
+
70
82
  function named(items, label) {
71
83
  const names = new Set();
72
84
  for (const item of items ?? []) {
@@ -84,7 +96,7 @@ export function readManifest(templateDirectory) {
84
96
  if (manifest.apiVersion !== "templates.domesystems.ai/v1" || manifest.kind !== "Template") throw new Error("template.yaml must declare apiVersion templates.domesystems.ai/v1 and kind Template.");
85
97
  if (!Array.isArray(manifest.agents) || manifest.agents.length === 0) throw new Error("template.yaml must declare at least one agent.");
86
98
  const agents = manifest.agents.map((entry, index) => {
87
- const agent = normalizeRuleFiles(root, expandAgent(root, entry, index), index);
99
+ const agent = normalizeManagedAgent(root, normalizeRuleFiles(root, expandAgent(root, entry, index), index), index);
88
100
  if (typeof agent.name !== "string" || !agent.name.trim()) throw new Error(`agents[${index}].name is required.`);
89
101
  const type = agent.type;
90
102
  if (!type) throw new Error(`agents[${index}].type is required.`);
@@ -93,8 +105,9 @@ export function readManifest(templateDirectory) {
93
105
  return { ...agent, type };
94
106
  });
95
107
  const filters = normalizeFilterConfigs(root, expandFilters(root, manifest.filters));
96
- named(agents, "agents"); named(manifest.gateways ?? [], "gateways"); named(manifest.tool_connections ?? [], "tool_connections"); named(manifest.models ?? [], "models"); named(manifest.pools ?? [], "pools"); named(filters, "filters");
97
- return { ...manifest, variables: manifest.variables ?? {}, gateways: manifest.gateways ?? [], tool_connections: manifest.tool_connections ?? [], models: manifest.models ?? [], pools: manifest.pools ?? [], filters, quotas: manifest.quotas ?? [], agents };
108
+ const triggers = manifest.triggers ?? [];
109
+ named(agents, "agents"); named(manifest.gateways ?? [], "gateways"); named(manifest.tool_connections ?? [], "tool_connections"); named(manifest.models ?? [], "models"); named(manifest.pools ?? [], "pools"); named(filters, "filters"); named(triggers, "triggers");
110
+ return { ...manifest, variables: manifest.variables ?? {}, gateways: manifest.gateways ?? [], tool_connections: manifest.tool_connections ?? [], models: manifest.models ?? [], pools: manifest.pools ?? [], filters, quotas: manifest.quotas ?? [], triggers, agents };
98
111
  }
99
112
 
100
113
  const PACKAGE_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?\/[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;