@suveren/gateway 0.19.3 → 0.19.5

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.
@@ -4,6 +4,12 @@ Learn the company, the team and the work, and collect real cases. Nothing is loa
4
4
 
5
5
  You ask; the person answers and checks. Ask one topic at a time and write down what you learn.
6
6
 
7
+ ## Before you start: the systems
8
+
9
+ Look at the systems in the header above. If a system the work needs is listed under **Available but not activated**, ask the person to activate it first (Integrations → its card → Activate) and read this guide again. Do not plan around a system you cannot see.
10
+
11
+ Plan the test only with the actions the connected systems offer — the header lists each system's changes and reads. If the work needs an action no system offers (for example a refund when the ERP has only quotes and orders), say so and agree with the person on what to test instead. Never pretend a system can do more than it does.
12
+
7
13
  ## What to ask, in this order
8
14
 
9
15
  1. **Company:** what it sells, to whom, in which currency, and which systems it uses. The systems connected to this gateway are listed in the header above; ask about the ones that matter for the work.
@@ -4,7 +4,7 @@ Turn the confirmed cases into test data and load it into the simulated systems.
4
4
 
5
5
  ## Build the package
6
6
 
7
- One package feeds every simulated system. Its format, and how to build a good one, is described in the `load_simulation` tool of each simulated system — read it there; it is the authority. In short: the company's `name` and `currency`, the `customers`, `products` and `contacts` the cases need, and the `cases` themselves (each request as it arrived and the reply that was actually sent).
7
+ One package feeds every simulated system. Its exact format is at the end of this guide (read from the simulated systems themselves), and how to build a good one is described there too. In short: the company's `name` and `currency`, the `customers`, `products` and `contacts` the cases need, and the `cases` themselves (each request as it arrived and the reply that was actually sent).
8
8
 
9
9
  - Include every customer, product and contact a case mentions, with stock, prices and credit limits that make each case answerable the way it really was.
10
10
  - Use only the renamed cases.
@@ -27,4 +27,7 @@ Clear and load each count against the setup mandate's daily limit, so one re-run
27
27
 
28
28
  The real replies stay inside the simulated email system. They are never shown to the working AI; they exist for comparing afterwards.
29
29
 
30
+
31
+ <!-- generated: package -->
32
+
30
33
  Next: **mandates**.
@@ -32,4 +32,7 @@ Apply this to whatever systems are connected: the header above lists each system
32
32
  - Sales, sending quotes and orders: review.
33
33
  - Email replies: review, recipients limited to the customers' domains.
34
34
 
35
+
36
+ <!-- generated: limits -->
37
+
35
38
  Next: **brief**.
@@ -10,5 +10,7 @@ What can make a test say more than it should, and what to do about each. Read th
10
10
  | Mandates too loose | A wrong result can look like success | Start in review mode or with low caps; loosen by replacing the mandate |
11
11
  | Proposals are stored readable on the Authority Server | The content of every proposal, including intents, can be read there | Test data and renamed cases only — never real customer data in a setup |
12
12
  | Setup limit too low | A clear without the following load leaves empty systems | Use a setup limit of 4–6 per day; clear and load in one go |
13
+ | An AI that can control a browser or the screen | It could open the gateway's page, read the API key there and approve its own proposals — the person would no longer decide | Never open or operate the gateway's page, never handle the API key, never approve. Tell the person to approve themselves, and to keep the gateway page out of any browser an AI controls |
14
+ | Calls around the Suveren tools | A terminal, HTTP or browser call to the gateway's ports is not governed by a mandate | Use only the Suveren tools. If something is missing, tell the person what — do not probe the gateway |
13
15
 
14
16
  Next: start a run — the person asks the working AI to work the new requests.
@@ -4079,6 +4079,12 @@ function agentVisibleAuthorizations(authorizations, integrationManager2) {
4079
4079
  );
4080
4080
  }
4081
4081
 
4082
+ // src/lib/agent-rules.ts
4083
+ var AGENT_RULES = [
4084
+ "Never open or operate the Suveren Gateway's web page \u2014 not in a browser you control, not with computer use. Never ask for, read or type the person's API key. Never approve a proposal: approvals are the person's alone.",
4085
+ "Use only the Suveren tools. No terminal, HTTP or browser calls to the gateway's ports (for example `curl localhost:3500/mcp`)."
4086
+ ];
4087
+
4082
4088
  // src/lib/mandate-brief.ts
4083
4089
  function shortProfileName(profileId) {
4084
4090
  const withoutVersion = profileId.replace(/@.*$/, "");
@@ -4165,6 +4171,10 @@ function buildMandateBrief(opts) {
4165
4171
  lines.push(canSetUp ? "If the person asks how to start with Suveren or how to set up their work with it: call setup__get_guide first and follow its steps in order." : `If the person asks how to start with Suveren: they first create a "Delegation" mandate in the Suveren Gateway at ${uiUrl()}. With it you can read the setup guide and lead them through the setup.`);
4166
4172
  lines.push("");
4167
4173
  }
4174
+ lines.push("=== RULES ===");
4175
+ lines.push("");
4176
+ for (const r of AGENT_RULES) lines.push(`- ${r}`);
4177
+ lines.push("");
4168
4178
  lines.push("When you receive a task, call list-authorizations(domain) to load full details for the relevant domain.");
4169
4179
  return lines.join("\n");
4170
4180
  }
@@ -5821,6 +5831,7 @@ var IntegrationManager = class {
5821
5831
  name: def.name,
5822
5832
  description: def.description ?? "",
5823
5833
  profile: def.profile,
5834
+ ...def.intentHint ? { intentHint: def.intentHint } : {},
5824
5835
  available: !def.simulationOnly || isSimulationMode()
5825
5836
  }));
5826
5837
  }
@@ -6861,7 +6872,7 @@ function loadGuides(builtinDir = builtinGuidesDir(), overrideDir = process.env.S
6861
6872
  }
6862
6873
  return [...byTopic.values()].sort((a, b) => a.order - b.order || a.topic.localeCompare(b.topic));
6863
6874
  }
6864
- function guideHeader(systems) {
6875
+ function guideHeader(systems, inactive = []) {
6865
6876
  const lines = [
6866
6877
  "> This guide is in English. Talk to the person in their language, and write the brief and mandate intents in the language the team uses.",
6867
6878
  "",
@@ -6879,13 +6890,75 @@ function guideHeader(systems) {
6879
6890
  lines.push(`- **${s.id}** \u2014 ${parts.join("; ")}`);
6880
6891
  }
6881
6892
  }
6893
+ if (inactive.length) {
6894
+ lines.push("");
6895
+ lines.push("**Available but not activated:** " + inactive.map((n) => `**${n}**`).join(", ") + ". Before anything else, ask the person to activate the ones the work needs: in the Suveren Gateway, Integrations \u2192 the system's card \u2192 Activate. Then read this guide again \u2014 a system you cannot see here does not exist for the test.");
6896
+ }
6882
6897
  lines.push("");
6883
6898
  lines.push(`**Approvals:** every mandate and brief you propose waits until the person approves it in the Suveren Gateway at ${uiUrl()}/approvals. Tell them each time you propose one.`);
6899
+ lines.push("");
6900
+ lines.push("**Rules:**");
6901
+ for (const r of AGENT_RULES) lines.push(`- ${r}`);
6884
6902
  return lines.join("\n");
6885
6903
  }
6904
+ function scopeFieldsOf(profile) {
6905
+ return profile.scopeSchema ?? profile.contextSchema;
6906
+ }
6907
+ function fieldLine(name, f) {
6908
+ const kind = [];
6909
+ const values = f.boundType?.values ?? f.enum;
6910
+ if (Array.isArray(values)) kind.push(`one of ${values.map((v) => `\`${String(v)}\``).join(", ")}`);
6911
+ else if (f.type) kind.push(f.type);
6912
+ if (f.unit) kind.push(f.unit);
6913
+ if (f.boundType?.window) kind.push(`per ${f.boundType.window === "daily" ? "day" : f.boundType.window}`);
6914
+ if (typeof f.maximum === "number") kind.push(`at most ${f.maximum}`);
6915
+ if (f.default !== void 0) kind.push(`default \`${String(f.default)}\``);
6916
+ const label = f.displayName ? ` (${f.displayName})` : "";
6917
+ return `- \`${name}\`${label} \u2014 ${kind.join(", ") || "value"}${f.description ? `. ${f.description}` : ""}`;
6918
+ }
6919
+ function fieldLines(schema) {
6920
+ const fields = schema?.fields ?? {};
6921
+ const order = (schema?.keyOrder ?? Object.keys(fields)).filter((k) => k !== "profile" && k !== "path" && fields[k]);
6922
+ return order.map((k) => fieldLine(k, fields[k]));
6923
+ }
6924
+ function limitsSection(systems) {
6925
+ const out = ["## Limits and scope per system", "", "From the profiles \u2014 use exactly these names in `create_mandate` (`limits` and `scope`). Every limit must be set.", ""];
6926
+ for (const s of systems) {
6927
+ if (!s.profile) continue;
6928
+ out.push(`### ${s.id} \u2014 profile \`${s.profile.id}\``, "", "**Limits:**", ...fieldLines(s.profile.boundsSchema));
6929
+ const scope2 = fieldLines(scopeFieldsOf(s.profile));
6930
+ out.push("", "**Scope:**", ...scope2.length ? scope2 : ["- none"], "");
6931
+ }
6932
+ return out.join("\n");
6933
+ }
6934
+ function packageSection(tool) {
6935
+ if (!tool?.inputSchema) return "## The package format\n\nNo simulated system with `load_simulation` is active \u2014 ask the person to activate one first.";
6936
+ const pkg = tool.inputSchema.properties?.package ?? tool.inputSchema;
6937
+ return [
6938
+ "## The package format",
6939
+ "",
6940
+ ...tool.description ? ["What the simulated systems say about it:", "", `> ${tool.description}`, ""] : [],
6941
+ "The `package` argument of `load_simulation` \u2014 the same package for every simulated system:",
6942
+ "",
6943
+ "```json",
6944
+ JSON.stringify(pkg, null, 2),
6945
+ "```"
6946
+ ].join("\n");
6947
+ }
6948
+ function fillGenerated(body, sections) {
6949
+ return body.replace(/<!--\s*generated:\s*([a-z-]+)\s*-->/g, (m, key) => sections[key] ? sections[key]() : m);
6950
+ }
6886
6951
 
6887
6952
  // src/lib/builtins/setup.ts
6888
- var DELEGATION_PROFILE = "github.com/humanagencyprotocol/hap-profiles/delegation@0.1";
6953
+ import { getProfile as getProfile7 } from "@hap/core";
6954
+ var DELEGATION_PROFILE = "delegation";
6955
+ var DELEGATION_INTENT_HINT = [
6956
+ "Why \u2014 With test data only, I want to find out which routine parts of my work an AI could take over, so people gain time \u2014 before anything touches real systems.",
6957
+ "",
6958
+ "Goal \u2014 Follow the setup guide: interview me about the company, the team and the work; prepare test data from real cases, renamed to .example names; propose the mandates and the working instructions (agent brief) that the AI doing the work will need.",
6959
+ "",
6960
+ "Watch out \u2014 You only propose; nothing happens until I approve it in the Suveren Gateway. Ask, don't guess: never invent a rule, a limit or a step. One proposal at a time. Steps customers would see start with my review. Never use real names or customer data \u2014 proposals are stored readable on the Suveren server. Never give the working AI a reporting mandate during a test run. Keep the setup and the working AI in separate conversations."
6961
+ ].join("\n");
6889
6962
  function briefRefusal(args) {
6890
6963
  if (typeof args.content !== "string" || args.content.trim() === "") return "`content` must be the complete new brief (markdown text).";
6891
6964
  const bytes = Buffer.byteLength(args.content, "utf-8");
@@ -6917,6 +6990,7 @@ function setupBuiltin(deps) {
6917
6990
  // card), not the internal "test setup" framing. Description is unchanged.
6918
6991
  name: "Delegation",
6919
6992
  description: "Your AI sets up a test of itself: it reads the setup guides and proposes its agent brief and its mandates. Every proposal waits for your approval. Simulation mode only.",
6993
+ intentHint: DELEGATION_INTENT_HINT,
6920
6994
  profile: DELEGATION_PROFILE,
6921
6995
  simulation: true,
6922
6996
  simulationOnly: true,
@@ -6965,7 +7039,10 @@ function setupBuiltin(deps) {
6965
7039
  handler: async (args) => {
6966
7040
  if (!isSimulationMode()) return { ...builtinText("Refused: not available outside simulation mode."), isError: true };
6967
7041
  const guides = loadGuides();
6968
- const header = guideHeader(connectedSystems(deps.integrationManager));
7042
+ const systems = connectedSystems(deps.integrationManager);
7043
+ const running = new Set(systems.map((s) => s.id));
7044
+ const inactive = getAllManifests().filter((m) => manifestIsSimulated(m) && !running.has(m.id)).map((m) => m.name);
7045
+ const header = guideHeader(systems, inactive);
6969
7046
  const topic = typeof args.topic === "string" ? args.topic.trim().toLowerCase() : "";
6970
7047
  if (!topic) {
6971
7048
  const list = guides.map((g, i) => `${i + 1}. **${g.topic}** \u2014 ${g.summary}`).join("\n");
@@ -6981,9 +7058,15 @@ Read each topic with get_guide(topic) before doing that step.`);
6981
7058
  if (!guide) {
6982
7059
  return { ...builtinText(`Unknown topic "${topic}". Topics: ${guides.map((g) => g.topic).join(", ") || "none installed"}.`), isError: true };
6983
7060
  }
7061
+ const body = fillGenerated(guide.body.trim(), {
7062
+ limits: () => limitsSection(systems.map((s) => ({ id: s.id, profile: getProfile7(s.profile) }))),
7063
+ package: () => packageSection(
7064
+ deps.integrationManager.getAllTools().find((t) => !deps.integrationManager.isBuiltin(t.integrationId) && t.originalName === "load_simulation")
7065
+ )
7066
+ });
6984
7067
  return builtinText(`${header}
6985
7068
 
6986
- ${guide.body.trim()}`);
7069
+ ${body}`);
6987
7070
  }
6988
7071
  },
6989
7072
  {