@zackbart/connecta-eve 0.41.0 → 0.42.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/README.md CHANGED
@@ -4,7 +4,7 @@ Connect an Eve agent to a Connecta agent pool and load its endpoint instructions
4
4
  once per turn. The helper runs in the Eve app; the Connecta server
5
5
  runs separately. No `@zackbart/connecta` dependency is installed by this package.
6
6
 
7
- Requires **Node 24+** and **Eve 1.0.0-rc.1**. Development and consumer
7
+ Requires **Node 24+** and **Eve 1.0.0-rc.4**. Development and consumer
8
8
  checks use that exact release candidate. The peer stays pinned during the RC
9
9
  period; later candidates and stable 1.0 need a compatibility check. Helper
10
10
  releases share Connecta's version and tag; choose the helper version matching
@@ -13,7 +13,7 @@ your server release.
13
13
  ## Install and add two files
14
14
 
15
15
  ```sh
16
- npm install @zackbart/connecta-eve eve@1.0.0-rc.1
16
+ npm install @zackbart/connecta-eve eve@1.0.0-rc.4
17
17
  ```
18
18
 
19
19
  The server must declare your agent, admit it to the named pool and issue its
@@ -31,10 +31,7 @@ Create `agent/connections/connecta.ts`:
31
31
  ```ts
32
32
  import { connectaConnection } from "@zackbart/connecta-eve";
33
33
 
34
- export default connectaConnection({
35
- pool: "assistant",
36
- description: "Shared CRM and tickets for the assistant.",
37
- });
34
+ export default connectaConnection({ pool: "assistant" });
38
35
  ```
39
36
 
40
37
  Create `agent/instructions/connecta.ts`:
@@ -45,6 +42,25 @@ import { connectaInstructions } from "@zackbart/connecta-eve";
45
42
  export default connectaInstructions({ pool: "assistant" });
46
43
  ```
47
44
 
45
+ `description` is optional. Eve shows it in its catalog listing and matches its
46
+ words against every search query for every tool of the connection, so the default
47
+ is a fixed neutral line. If you set one, describe the domain in prose, such as
48
+ `"Member records, giving and event registration."`. Do not list connectors or
49
+ operations: on a three-connector meta pool, `"CRM, invoices and tickets"` made the
50
+ query `"invoices"` return all six routing tools, 9.4 KB measured, and tells the
51
+ model nothing about the operations behind them. The instructions carry the roster.
52
+ A string such as
53
+ `"Company tools through Connecta"` tells the model nothing, so the helper warns
54
+ at startup.
55
+
56
+ Eve names a connection after its file. If yours is not `connecta.ts`, say so in
57
+ the instructions, or the model is told tool names that do not exist:
58
+
59
+ ```ts
60
+ // agent/connections/workspace.ts gives the model workspace__* tools.
61
+ export default connectaInstructions({ pool: "assistant", connection: "workspace" });
62
+ ```
63
+
48
64
  Both factories accept `url` to override `CONNECTA_URL`. With `pool`, the URL is
49
65
  `<url>/agent/<pool>`; without `pool`, supply the complete endpoint URL. Pool
50
66
  names must match `[a-z0-9_-]+`. `connectaEndpoint({ url, pool })` returns the same
@@ -56,6 +72,16 @@ again for each request, so rotation requires no process restart. A `getToken`
56
72
  callback can return a string or a promise of one; it overrides the environment.
57
73
  No user's identity is forwarded.
58
74
 
75
+ `headers` adds request headers beside the bearer, such as a service token for an
76
+ edge in front of Connecta. Pass the same value to every factory. A function runs
77
+ for each request, so a rotated secret needs no restart. On guidance and skill
78
+ requests, the helper's own `Authorization` and MCP protocol headers always win.
79
+
80
+ ```ts
81
+ const headers = () => ({ "X-Edge-Token": process.env.EDGE_TOKEN ?? "" });
82
+ export default connectaConnection({ pool: "assistant", headers });
83
+ ```
84
+
59
85
  ## Choosing the pool at runtime
60
86
 
61
87
  Pass the same selector to both factories when the pool depends on the chat.
@@ -112,16 +138,40 @@ use consistent trusted policy data as with a dynamic pool selector. This policy
112
138
  controls what the app offers; Connecta still enforces endpoint authorization.
113
139
  No Eve dynamic-value unwrapping is required.
114
140
 
115
- ## Upgrading to Eve 1.0 RC
141
+ ## Upgrading to Eve 1.0.0-rc.4
116
142
 
117
- Update the app to `eve@1.0.0-rc.1` and reinstall to refresh its lockfile.
118
- The helper's connection, dynamic pool, instructions and approval APIs use Eve's
119
- stable entry points and require no authoring changes for this RC. Eve's
143
+ Update the app to `eve@1.0.0-rc.4`, reinstall to refresh its lockfile, then
144
+ rebuild and test it before deploying. The helper's connection, dynamic pool,
145
+ instructions and approval APIs use Eve's stable entry points and require no
146
+ authoring changes for this RC. Eve's
120
147
  [1.0 stability policy](https://eve.dev/docs/reference/typescript-api#stability-policy)
121
148
  does not cover `experimental` fields or internal modules.
122
149
 
123
- From 0.90, review the intervening
124
- [release notes](https://github.com/vercel/eve/blob/eve%401.0.0-rc.1/packages/eve/CHANGELOG.md):
150
+ From rc.1, review Eve's
151
+ [rc.2](https://github.com/vercel/eve/releases/tag/eve%401.0.0-rc.2),
152
+ [rc.3](https://github.com/vercel/eve/releases/tag/eve%401.0.0-rc.3) and
153
+ [rc.4](https://github.com/vercel/eve/releases/tag/eve%401.0.0-rc.4) release notes.
154
+ These change app-owned code and deployments the helper does not manage:
155
+
156
+ - **Rollback.** Session checkpoints move to version 19 (rc.3). A deployment from
157
+ before rc.3 refuses to take over a session rc.3 or later wrote, so that session
158
+ stays on the deployment that wrote it. New runs also use Workflow spec 9; set
159
+ `WORKFLOW_SPEC_VERSION=8` to keep creating spec 8 runs.
160
+ - **File tools.** Every agent gets a default `edit_file` tool (rc.4) that changes
161
+ sandbox files without `write_file`. If you disable, wrap or gate `write_file`,
162
+ do the same for `edit_file`. Connecta's own tools are unaffected.
163
+ - **Builds.** Eve moves to a Nitro 3 release candidate and declares Rolldown
164
+ itself (rc.3). Importing `nitro/storage`, `nitro/kv` or `nitro/database` from
165
+ agent code now fails the build, as does an asset import that leaves the authored
166
+ package.
167
+ - **Code extension.** `code__grep`, `code__worker` and `code__apply_patch` are gone
168
+ (rc.3, rc.4). Follow Eve's notes if your app mounts `eve/extensions/code`.
169
+ - **Dynamic tools.** A dynamic tool no longer replaces a static tool of the same
170
+ name (rc.3). Dynamic connections, including this helper's, still override a
171
+ static connection of the same name.
172
+
173
+ From 0.90, also review the
174
+ [rc.1 release notes](https://github.com/vercel/eve/blob/eve%401.0.0-rc.1/packages/eve/CHANGELOG.md):
125
175
  `session.clear()` now cancels running turns and tasks, and object-form connection
126
176
  approvals are now preserved at runtime. RC.1 also requires `@vercel/connect`
127
177
  `^2.7.0` when that optional integration is installed; older Connect releases
@@ -165,12 +215,38 @@ any tool whose `readOnlyHint` is not `true`, including writable `execute_code`.
165
215
  `approval`, either a policy or an approval configuration, takes precedence over
166
216
  `gateWrites`.
167
217
 
168
- The gate uses the host's cached annotations. If a read becomes a write before
169
- dispatch, Connecta applies its current classification; a writable pool can
170
- execute the write without a fresh approval. A read-only pool refuses it.
218
+ An agent-wide `approval` in Eve's `agent.ts` runs beside the connection's policy
219
+ and the stricter result wins. It can add a gate to Connecta tools, including under
220
+ the default `never()`, and cannot remove one that `gateWrites` set.
221
+
222
+ The gate uses the host's cached annotations. If a native tool becomes a write, its cached read name is refused before dispatch. Refresh `tools/list` and use the write's name; approval follows the host's policy. Read-only pools refuse writes.
171
223
 
172
224
  ## Endpoint instructions
173
225
 
226
+ Eve hides MCP tools behind `eve__tool` under a `<connection>__` prefix, and
227
+ `eve__search` covers listed tools only. Connecta's text is host-neutral, so the
228
+ helper places an Eve guide before it, built from the endpoint's
229
+ [facts](https://github.com/zackbart/connecta/blob/main/documentation/meta-tools.md#endpoint-facts):
230
+
231
+ - **Meta pools:** call `eve__tool({ name: "connecta__execute_code", input })`
232
+ directly, with a short example program. `eve__search` sees the routing tools and
233
+ never a downstream operation, so its empty result does not mean a capability is
234
+ missing. Reachable connectors are listed by id.
235
+ - **Native pools:** a read is `connecta__<connector>__<tool>` and a write
236
+ `connecta__<connector>__WRITE__<tool>`. Scope a search with
237
+ `"connecta__<connector>__"`, use `execute_code` for several, dependent or reduced
238
+ calls (omitted when the pool has none), and when tools are missing get a link from
239
+ `connecta__authorize_connector` for the user or operator. Eve lists tools again on
240
+ each step, so the repair needs no reconnect, unlike a host that keeps its first
241
+ list.
242
+ - **Older servers without facts:** only the naming rule.
243
+
244
+ The guide adds about 600 bytes with three connectors. Its roster stays under 512
245
+ bytes: titles go first, then whole entries give way to a `+N more` count. Names
246
+ in Connecta's text and in `nextAction` stay unprefixed, and the guide says so.
247
+ The helper warns once per endpoint when a server named `connecta` is on a
248
+ different major or minor release from the helper.
249
+
174
250
  Instructions use `server/discover` (MCP 2026-07-28), falling back to legacy
175
251
  `initialize` when discovery returns a response without guidance, including a
176
252
  non-OK status or an unsupported-method response. Network errors and timeouts
@@ -225,7 +301,7 @@ custom audience, even when Vercel signed them.
225
301
 
226
302
  In a source checkout with dependencies installed and both packages built, run
227
303
  `pnpm --filter @zackbart/connecta-eve run probe:catalog --output /absolute/path/outside/checkout`
228
- on Node 24. This boots real Eve 1.0.0-rc.1 with a packed, installed helper against
304
+ on Node 24. This boots real Eve 1.0.0-rc.4 with a packed, installed helper against
229
305
  seeded local catalogs of 40, 100, 250, 500, and 1,000 downstream tools on the
230
306
  meta, native, and native-plus-code surfaces. Native listings include three
231
307
  Connecta tools beyond the downstream count. A 1,001-tool native catalog must
@@ -235,8 +311,11 @@ The probe uses Eve's public language-model interface with a deterministic local
235
311
  transport, without model credentials or paid calls. It measures construction,
236
312
  cold and warm discovery, schema and result bytes, call counts, concurrent-call
237
313
  isolation, bounded-result paging, and process memory. Fresh child processes
238
- isolate each matrix cell; Eve startup is separate from turn latency. Reports
239
- retain actual Eve events and transport inputs. Token usage and model task
314
+ isolate each matrix cell; Eve startup is separate from turn latency. Each turn
315
+ also checks what the helper's guide claims about Eve: guidance arrives as its own
316
+ system message on every model call, `eve__search` on a meta pool reaches only
317
+ routing tools, native writes are named `connecta__<connector>__WRITE__<tool>`, and
318
+ every step lists tools again. Reports retain actual Eve events and transport inputs. Token usage and model task
240
319
  quality remain unmeasured; these results establish local runtime contracts,
241
320
  not live Vercel workload admission or production model performance.
242
321
 
@@ -262,7 +341,7 @@ export default connectaSkill({
262
341
  });
263
342
  ```
264
343
 
265
- This uses the pinned Eve 1.0.0-rc.1 public `defineSkill` and `defineDynamic`
344
+ This uses the pinned Eve 1.0.0-rc.4 public `defineSkill` and `defineDynamic`
266
345
  APIs. Eve's deferred discovery searches the description; loading adds only
267
346
  instructions. It never installs tools. Use the same caller predicate and pool
268
347
  selector as the connection. A false or throwing predicate skips selection,
package/dist/index.d.ts CHANGED
@@ -14,7 +14,15 @@ export interface ConnectaEndpointOptions {
14
14
  * no restart. Defaults to the `CONNECTA_ACCESS_TOKEN` environment variable.
15
15
  */
16
16
  getToken?: () => string | Promise<string>;
17
+ /**
18
+ * Extra request headers, such as a service token for an edge in front of
19
+ * Connecta. A function is resolved on every request. These never replace
20
+ * the helper's bearer or MCP protocol headers on guidance requests.
21
+ */
22
+ headers?: ConnectaHeaders;
17
23
  }
24
+ /** Fixed headers, or a resolver called on every request. */
25
+ export type ConnectaHeaders = Readonly<Record<string, string>> | (() => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>);
18
26
  /** App-owned pool policy; use `ctx.memo` when its result should stay fixed. */
19
27
  export type ConnectaPoolSelector = (ctx: DynamicContext) => string | Promise<string>;
20
28
  /** App-owned caller/turn policy, evaluated before selecting a pool or fetching guidance. */
@@ -24,8 +32,13 @@ export interface ConnectaConnectionOptions extends Omit<ConnectaEndpointOptions,
24
32
  pool?: string | ConnectaPoolSelector;
25
33
  /** Omit this value when false or when the policy throws. Evaluated every model call. */
26
34
  when?: ConnectaPredicate;
27
- /** What the connection offers, for the model choosing which connection to search. */
28
- description: string;
35
+ /**
36
+ * What the connection offers, in Eve's catalog listing and in the words every
37
+ * tool of this connection matches in `eve__search`. Defaults to a fixed
38
+ * neutral line. Describe the domain in prose; do not list connectors or
39
+ * operations here, because a query naming one then matches every tool.
40
+ */
41
+ description?: string;
29
42
  /** Eve's approval for every Connecta tool: a policy or configuration. Defaults to `never()`. */
30
43
  approval?: Approval;
31
44
  /**
@@ -40,6 +53,11 @@ export interface ConnectaInstructionsOptions extends Omit<ConnectaEndpointOption
40
53
  pool?: string | ConnectaPoolSelector;
41
54
  /** Omit this value when false or when the policy throws. Evaluated every model call. */
42
55
  when?: ConnectaPredicate;
56
+ /**
57
+ * The Eve connection's name, which is its file under `agent/connections/`.
58
+ * The model calls `<connection>__<tool>`. Default `connecta`.
59
+ */
60
+ connection?: string;
43
61
  /** MCP client name for instruction requests. Default `connecta-eve-instructions`. */
44
62
  clientName?: string;
45
63
  /** How long fetched instructions are reused. Default ten minutes. */
@@ -79,7 +97,7 @@ export declare function connectaConnection(options: ConnectaConnectionOptions):
79
97
  */
80
98
  export declare function connectaInstructions(options?: ConnectaInstructionsOptions): import("eve/skills").DynamicSentinel<import("eve/instructions").DynamicInstructionsResult, DynamicContext>;
81
99
  /** One explicitly selected Connecta guide projected as a deferred Eve skill. */
82
- export interface ConnectaSkillOptions extends ConnectaInstructionsOptions {
100
+ export interface ConnectaSkillOptions extends Omit<ConnectaInstructionsOptions, "connection"> {
83
101
  /** Exact skills-tool name, for example `connector:crm`. */
84
102
  name: string;
85
103
  /** Short task selector Eve can search without loading the guide. */
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { defineDynamic as defineDynamicSkill, defineSkill } from "eve/skills";
2
2
  import { defineDynamic as defineDynamicConnection, defineMcpClientConnection, } from "eve/connections";
3
3
  import { defineDynamic, defineInstructions } from "eve/instructions";
4
4
  import { never } from "eve/tools/approval";
5
+ import { CONNECTA_VERSION } from "./version.js";
5
6
  function environment(name) {
6
7
  const value = globalThis.process?.env?.[name];
7
8
  return value?.trim() || undefined;
@@ -33,6 +34,7 @@ async function tokenFor(options) {
33
34
  */
34
35
  export const gateConnectaWrites = ({ toolAnnotations }) => toolAnnotations?.readOnlyHint === true ? "not-applicable" : "user-approval";
35
36
  export function connectaConnection(options) {
37
+ warnOnGenericDescription(options.description);
36
38
  const { pool, ...rest } = options;
37
39
  if (typeof pool === "function" || options.when) {
38
40
  return defineDynamicConnection(async (ctx) => {
@@ -50,11 +52,25 @@ export function connectaConnection(options) {
50
52
  }
51
53
  return connectionDefinition(options, connectaEndpoint(pool === undefined ? rest : { ...rest, pool }));
52
54
  }
55
+ /**
56
+ * Eve matches these words against every search query, and a short word also
57
+ * matches longer query words ("use" hits "users"), so this avoids common stems.
58
+ */
59
+ const DEFAULT_DESCRIPTION = "Connecta integration gateway.";
60
+ /** "Company tools through Connecta" and other strings any Connecta connection could claim. */
61
+ const GENERIC_DESCRIPTION = /\b(?:tools?|services?|integrations?|apps?)\s+(?:through|via|from|using|on|in|with)\s+connecta\b|^\W*(?:(?:the|our|all|my|company|connecta|mcp|tools?|services?|integrations?|connections?|gateway|server|access|through|via|using)\W*)*$/i;
62
+ function warnOnGenericDescription(description) {
63
+ if (description === undefined || !GENERIC_DESCRIPTION.test(description))
64
+ return;
65
+ console.warn(`[connecta-eve] Connection description ${JSON.stringify(description)} gives the model no domain information. Omit it, or say what this agent reaches in prose without listing connectors.`);
66
+ }
53
67
  function connectionDefinition(options, endpoint, instanceKey) {
68
+ const { headers } = options;
54
69
  return defineMcpClientConnection({
55
70
  url: endpoint,
56
71
  ...(instanceKey === undefined ? {} : { instanceKey }),
57
- description: options.description,
72
+ description: options.description ?? DEFAULT_DESCRIPTION,
73
+ ...(headers === undefined ? {} : { headers: typeof headers === "function" ? () => headers() : headers }),
58
74
  auth: {
59
75
  principalType: "app",
60
76
  getToken: async () => ({ token: await tokenFor(options) }),
@@ -70,18 +86,108 @@ async function enabled(when, ctx) {
70
86
  return false;
71
87
  }
72
88
  }
73
- /** Connecta's MCP `instructions` for one endpoint, or null when unavailable. */
89
+ /** Older servers omit the extension; anything malformed reads the same way. */
90
+ function endpointFacts(value) {
91
+ const facts = value;
92
+ if (facts?.surface !== "meta" && facts?.surface !== "native")
93
+ return undefined;
94
+ if (typeof facts.executeCode !== "boolean" || !Array.isArray(facts.connectors))
95
+ return undefined;
96
+ const text = (field) => (typeof field === "string" ? field.replace(/\s+/g, " ").trim() : "");
97
+ return {
98
+ surface: facts.surface,
99
+ executeCode: facts.executeCode,
100
+ readOnly: facts.readOnly === true,
101
+ connectors: facts.connectors.flatMap((connector) => {
102
+ const id = text(connector?.id);
103
+ if (!id)
104
+ return [];
105
+ const title = text(connector.title);
106
+ const readFirst = text(connector.readFirst);
107
+ return [{ id, ...(title ? { title } : {}), ...(readFirst ? { readFirst } : {}) }];
108
+ }),
109
+ };
110
+ }
111
+ const ROSTER_MAX_BYTES = 512;
112
+ /** Detail degrades before names do, as the server's own inventory does. */
113
+ function connectorRoster(facts, prefix) {
114
+ const fits = (line) => new TextEncoder().encode(line).length <= ROSTER_MAX_BYTES;
115
+ const entry = ({ id, title, readFirst }, withTitle) => {
116
+ const notes = [
117
+ ...(withTitle && title ? [title] : []),
118
+ // A native tool's description already carries its guide pointer.
119
+ ...(readFirst && facts.surface === "meta" ? [`read first: ${prefix}skills { name: "${readFirst}" }`] : []),
120
+ ];
121
+ return notes.length ? `${id} (${notes.join("; ")})` : id;
122
+ };
123
+ for (const withTitle of [true, false]) {
124
+ const line = facts.connectors.map((connector) => entry(connector, withTitle)).join(", ");
125
+ if (fits(line))
126
+ return line;
127
+ }
128
+ const entries = facts.connectors.map((connector) => entry(connector, false));
129
+ let shown = 0;
130
+ while (fits(`${entries.slice(0, shown + 1).join(", ")}; +${entries.length - shown - 1} more`))
131
+ shown++;
132
+ return `${entries.slice(0, shown).join(", ")}${shown ? "; " : ""}+${entries.length - shown} more`;
133
+ }
134
+ /**
135
+ * How Eve's deferred catalog reaches this endpoint's tools. Connecta's own text
136
+ * names tools as MCP lists them; Eve adds the connection prefix and hides them
137
+ * behind `eve__tool`, and its search covers listed tools only.
138
+ */
139
+ function eveGuide(connection, facts) {
140
+ const prefix = `${connection}__`;
141
+ if (!facts) {
142
+ return `Connecta tools are deferred: call eve__tool({ name: "${prefix}<tool>", input }). Names in this guidance and in nextAction omit the "${prefix}" prefix.`;
143
+ }
144
+ const roster = facts.connectors.length ? connectorRoster(facts, prefix) : undefined;
145
+ if (facts.surface === "meta") {
146
+ return `Connecta tools are deferred: call eve__tool({ name: "${prefix}<tool>", input }). Names in this guidance and in nextAction omit the "${prefix}" prefix. Go straight to ${prefix}execute_code without eve__search, input { code: "async () => { const { tools } = await connecta.search({ query: 'list invoices', safety: 'readOnly' }); const r = await connecta.call(tools[0].address, {}); return r.data; }" }. eve__search sees only Connecta's routing tools, never downstream operations, so empty results do not mean a capability is missing; search inside the program.${roster ? ` Reachable: ${roster}.` : ""}`;
147
+ }
148
+ return `Connecta tools are deferred: call eve__tool({ name: "${prefix}<connector>__<tool>", input })${facts.readOnly ? "" : `, with writes named "${prefix}<connector>__WRITE__<tool>"`}. Find them with eve__search; scope one connector with "${prefix}<connector>__", not "<connector>__". Names in this guidance and in nextAction omit "${prefix}".${facts.executeCode ? ` For several, dependent or reduced calls, go straight to ${prefix}execute_code with { code: "async () => { ... }" }, using each tool's Program address.` : ""} Tools missing: ${prefix}authorize_connector returns a link; give it to the user or operator once and stop. Eve lists tools again every step, so a repair needs no reconnect.${roster ? ` Connectors: ${roster}.` : ""}`;
149
+ }
150
+ /** Release lines a helper and server must share; a patch difference is compatible. */
151
+ const releaseLine = (version) => typeof version === "string" ? /^(\d+\.\d+)\./.exec(version)?.[1] : undefined;
152
+ /** An endpoint may embed credentials or a token in its URL, path included; logs get only its origin. */
153
+ function loggableEndpoint(endpoint) {
154
+ try {
155
+ return new URL(endpoint).origin;
156
+ }
157
+ catch {
158
+ return "the configured endpoint";
159
+ }
160
+ }
161
+ /** A deployment that renamed its server may version it independently, so only `connecta` is compared. */
162
+ function warnOnVersionSkew(endpoint, server) {
163
+ if (server?.name !== "connecta")
164
+ return;
165
+ const line = releaseLine(server.version);
166
+ if (line === undefined || line === releaseLine(CONNECTA_VERSION))
167
+ return;
168
+ // The version is remote text, so only its validated numeric line reaches logs.
169
+ console.warn(`[connecta-eve] Helper ${CONNECTA_VERSION} and Connecta ${line}.x at ${loggableEndpoint(endpoint)} are different releases. Install the helper matching your server.`);
170
+ }
171
+ /** Headers for a guidance request. The caller's extras can never replace what the request itself needs. */
172
+ async function guidanceHeaders(options, own) {
173
+ const extra = typeof options.headers === "function" ? await options.headers() : options.headers;
174
+ const headers = new Headers(extra);
175
+ for (const [name, value] of Object.entries(own))
176
+ headers.set(name, value);
177
+ return Object.fromEntries(headers);
178
+ }
179
+ /** Connecta's MCP `instructions` and endpoint facts for one endpoint, or null when unavailable. */
74
180
  async function instructionRequest(options, endpoint, method, signal) {
75
181
  const modern = method === "server/discover";
76
182
  const clientInfo = { name: options.clientName ?? "connecta-eve-instructions", version: "1" };
77
183
  const response = await (options.fetch ?? fetch)(endpoint, {
78
184
  method: "POST",
79
- headers: {
185
+ headers: await guidanceHeaders(options, {
80
186
  Authorization: `Bearer ${await tokenFor(options)}`,
81
187
  "Content-Type": "application/json",
82
188
  Accept: "application/json, text/event-stream",
83
189
  ...(modern ? { "MCP-Protocol-Version": "2026-07-28", "Mcp-Method": method } : {}),
84
- },
190
+ }),
85
191
  body: JSON.stringify({
86
192
  jsonrpc: "2.0",
87
193
  id: 1,
@@ -114,8 +220,15 @@ async function instructionRequest(options, endpoint, method, signal) {
114
220
  ?.slice("data:".length);
115
221
  if (!json)
116
222
  return null;
117
- const instructions = JSON.parse(json).result?.instructions;
118
- return typeof instructions === "string" && instructions.trim() ? instructions.trim() : null;
223
+ const { result } = JSON.parse(json);
224
+ const instructions = result?.instructions;
225
+ if (typeof instructions !== "string" || !instructions.trim())
226
+ return null;
227
+ return {
228
+ instructions: instructions.trim(),
229
+ facts: endpointFacts(result?.capabilities?.extensions?.["dev.connecta/endpoint"]),
230
+ server: result?._meta?.["io.modelcontextprotocol/serverInfo"] ?? result?.serverInfo,
231
+ };
119
232
  }
120
233
  async function fetchConnectaInstructions(options, endpoint, signal) {
121
234
  // Only a completed discovery response can justify legacy negotiation.
@@ -133,6 +246,10 @@ async function fetchConnectaInstructions(options, endpoint, signal) {
133
246
  */
134
247
  export function connectaInstructions(options = {}) {
135
248
  const ttlMs = options.ttlMs ?? 600_000;
249
+ const connection = options.connection ?? "connecta";
250
+ if (!/^[A-Za-z0-9._-]+$/.test(connection)) {
251
+ throw new Error(`Connecta connection "${connection}" must be the file name under agent/connections.`);
252
+ }
136
253
  const endpoints = new Map();
137
254
  const current = async (endpoint, signal) => {
138
255
  signal.throwIfAborted();
@@ -146,7 +263,13 @@ export function connectaInstructions(options = {}) {
146
263
  return cached?.content ?? null;
147
264
  let fresh;
148
265
  try {
149
- fresh = await fetchConnectaInstructions(options, endpoint, signal);
266
+ const guidance = await fetchConnectaInstructions(options, endpoint, signal);
267
+ if (guidance && !state.versionChecked) {
268
+ state.versionChecked = true;
269
+ warnOnVersionSkew(endpoint, guidance.server);
270
+ }
271
+ // Eve's half comes first: it says how to read every name in Connecta's own text.
272
+ fresh = guidance && `${eveGuide(connection, guidance.facts)}\n${guidance.instructions}`;
150
273
  }
151
274
  catch {
152
275
  // Eve's cancellation is not an endpoint failure: rethrowing keeps it out
@@ -203,14 +326,14 @@ export function connectaSkill(options) {
203
326
  try {
204
327
  const response = await (options.fetch ?? fetch)(endpoint, {
205
328
  method: "POST",
206
- headers: {
329
+ headers: await guidanceHeaders(options, {
207
330
  Authorization: `Bearer ${await tokenFor(options)}`,
208
331
  "Content-Type": "application/json",
209
332
  Accept: "application/json, text/event-stream",
210
333
  "MCP-Protocol-Version": "2026-07-28",
211
334
  "Mcp-Method": "tools/call",
212
335
  "Mcp-Name": "skills",
213
- },
336
+ }),
214
337
  body: JSON.stringify({
215
338
  jsonrpc: "2.0",
216
339
  id: 1,
@@ -0,0 +1 @@
1
+ export declare const CONNECTA_VERSION = "0.42.0";
@@ -0,0 +1,3 @@
1
+ // Generated from package.json by scripts/generate-version.mjs.
2
+ // Workers-safe: no runtime filesystem read or deployment override.
3
+ export const CONNECTA_VERSION = "0.42.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta-eve",
3
- "version": "0.41.0",
3
+ "version": "0.42.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Eve connection and instructions helpers for Connecta agent endpoints.",
@@ -28,11 +28,11 @@
28
28
  }
29
29
  },
30
30
  "peerDependencies": {
31
- "eve": "1.0.0-rc.1"
31
+ "eve": "1.0.0-rc.4"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^24.19.2",
35
- "eve": "1.0.0-rc.1",
35
+ "eve": "1.0.0-rc.4",
36
36
  "typescript": "^6.0.3",
37
37
  "vite": "^8.3.4",
38
38
  "vitest": "^5.0.4"