@zackbart/connecta 0.12.1 → 0.13.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +4 -1
  3. package/dist/apps-shell.d.ts +13 -11
  4. package/dist/apps-shell.d.ts.map +1 -1
  5. package/dist/apps-shell.js +221 -30
  6. package/dist/apps-shell.js.map +1 -1
  7. package/dist/catalog-service.d.ts +41 -0
  8. package/dist/catalog-service.d.ts.map +1 -1
  9. package/dist/catalog-service.js +94 -5
  10. package/dist/catalog-service.js.map +1 -1
  11. package/dist/connectors/api.d.ts +5 -4
  12. package/dist/connectors/api.d.ts.map +1 -1
  13. package/dist/connectors/api.js.map +1 -1
  14. package/dist/connectors/remote-mcp.d.ts +5 -4
  15. package/dist/connectors/remote-mcp.d.ts.map +1 -1
  16. package/dist/connectors/remote-mcp.js.map +1 -1
  17. package/dist/execute.d.ts +12 -4
  18. package/dist/execute.d.ts.map +1 -1
  19. package/dist/execute.js +142 -20
  20. package/dist/execute.js.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/meta-tools.d.ts.map +1 -1
  25. package/dist/meta-tools.js +14 -4
  26. package/dist/meta-tools.js.map +1 -1
  27. package/dist/providers/mixpanel.d.ts +21 -0
  28. package/dist/providers/mixpanel.d.ts.map +1 -0
  29. package/dist/providers/mixpanel.js +183 -0
  30. package/dist/providers/mixpanel.js.map +1 -0
  31. package/dist/skills.d.ts +7 -9
  32. package/dist/skills.d.ts.map +1 -1
  33. package/dist/skills.js +60 -25
  34. package/dist/skills.js.map +1 -1
  35. package/dist/types.d.ts +26 -6
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/documentation/code-mode.md +32 -20
  40. package/documentation/connectors.md +116 -4
  41. package/documentation/mcp-ui-design.md +8 -8
  42. package/documentation/meta-tools.md +80 -8
  43. package/documentation/mixpanel.md +72 -0
  44. package/documentation/program-ui-read-calls.md +213 -0
  45. package/ethos.md +10 -4
  46. package/package.json +5 -1
  47. package/src/apps-shell.ts +221 -30
  48. package/src/catalog-service.ts +139 -4
  49. package/src/connectors/api.ts +5 -3
  50. package/src/connectors/remote-mcp.ts +5 -3
  51. package/src/execute.ts +215 -21
  52. package/src/index.ts +1 -0
  53. package/src/meta-tools.ts +19 -4
  54. package/src/providers/mixpanel.ts +220 -0
  55. package/src/skills.ts +66 -24
  56. package/src/types.ts +27 -6
  57. package/src/version.ts +1 -1
  58. package/templates/node/package.json +1 -1
package/src/skills.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import type { Connector } from "./types.js";
2
2
 
3
3
  export const CONNECTA_INSTRUCTIONS =
4
- 'Connecta exposes integrations behind seven meta-tools, and execute_code is the primary one: write an async arrow function and use connecta.search (empty query browses every catalog), connecta.describe, connecta.call, and connecta.batch inside it for discovery, two or more calls, dependent steps, loops, joins, and reducing large results before they reach you. For a single read at an unknown address, search_tools with 2–4 distinctive action/object terms and includeSchemas="compact", then one call_tool a lone cold call is cheaper direct than through a program. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: "usage" }).';
4
+ 'Connecta exposes seven meta-tools. For one read at an unknown address, search_tools with 2–4 distinctive action/object terms and includeSchemas="compact", then one call_tool a lone cold call is cheaper direct than a program. For read-only reduction, multiple or dependent calls, loops, joins, or branches, do not call top-level search_tools: make one execute_code call whose program searches, selects, calls, and reduces; never return discovery for another call. connecta.ui(html) is a guest function inside execute_code, never a connector address or search_tools result; pass one HTML string for display-only, or bind named read-only refresh/drill-down calls in its optional reads argument, and return the same initial summary data the HTML renders. Unannotated, write-capable, or destructive tools stay top level: search_tools, then call_destructive_tool; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: "usage" }).';
5
5
 
6
- export const USAGE_SKILL = `# Connecta usage
6
+ const USAGE_SKILL_BASE = `# Connecta usage
7
7
 
8
8
  ## The surface
9
9
 
@@ -23,7 +23,7 @@ Use exact addresses from discovery; never invent one. Search 2–4 distinctive a
23
23
 
24
24
  One async arrow function. The only capabilities are one global per connector (\`<connectorId>.<toolName>(args)\`), the \`connecta\` functions, and \`console.log\`.
25
25
 
26
- - \`connecta.search({})\` browses every catalog; \`safety: "readOnly"\` narrows to calls a program can execute, \`connector: "<id>"\` to one. This filters results, not authority; matches carry \`address\` and annotations.
26
+ - \`connecta.search({})\` loads all catalogs; pass \`connector: "<id>"\` when obvious to load one. \`safety: "readOnly"\` keeps executable calls. Neither grants authority. Matches carry \`address\` and annotations.
27
27
  - Exact schemas: \`connecta.describe({ address: "connector.tool" })\` for one, \`{ addresses: [...] }\` for many; \`format: "json"\` only for exact constraints.
28
28
  - Two to ten independent calls: \`connecta.batch([...])\`. Each outcome is \`{ address, ok: true, data }\` or \`{ address, ok: false, error, errorDetails: { code, retryable } }\` — how a program tells a policy refusal from a transient failure.
29
29
  - Search inside the run, not before it; return only the reduction the answer needs, never raw payloads.
@@ -31,21 +31,20 @@ One async arrow function. The only capabilities are one global per connector (\`
31
31
 
32
32
  ## Rendering a view
33
33
 
34
- \`connecta.ui(html)\` renders one view per successful run for the client, never for the model. Fetch first, check the shape in code. On a surprise — empty array, missing key — return a trimmed first record instead of rendering: the wrong view becomes the sample you needed. Otherwise render from the variables you return; the model reads the return value, not the view.
34
+ \`connecta.ui(html)\` renders a display-only view on success for the client, never for the model. Fetch first, check the shape in code. On a surprise — empty array, missing key — return a trimmed first record instead of rendering: the wrong view becomes the sample you needed. Otherwise render from the variables you return; the model reads the return value, not the view.
35
+
35
36
  `;
36
37
 
37
- /**
38
- * Appended to USAGE_SKILL only when the deployment actually has at least one
39
- * connector guide. A deployment with none — every deployment that has not
40
- * adopted the feature — keeps the base guide byte-for-byte, rather than paying
41
- * context for an instruction to fetch guides that do not exist.
42
- */
43
- export const CONNECTOR_GUIDES_SECTION = `
38
+ /** Deployment-scoped guide routing appended to the shared usage guide. */
39
+ const CONNECTOR_GUIDES_SECTION = `
44
40
  ## Per-connector guides
45
41
 
46
- Some connectors here ship their own usage guide preferred tools, address quirks, pagination conventions, rate-limit etiquette, query patterns. \`skills({})\` lists each one as \`connector:<connectorId>\`; fetch it with \`skills({ name: "connector:<connectorId>" })\`. \`search_tools\`, \`connecta.search\`, and \`connecta.describe\` set \`guide\` on matches whose connector has one. Read a connector's guide before working with it for the first time in a task.
42
+ When a connector here ships a deployment-scoped usage guide, \`skills({})\` and discovery return the exact \`guide\` name plus a bounded \`guideSummary\` saying what it covers. Fetch only a listed or carried name with \`skills({ name: <guide> })\`; never infer one from a connector id. \`guideRequired: true\` is a hard stop: fetch before calling. \`guideRequiredReasons\` says why — \`connector_required\` and \`approval_required\` stand however you expand the schema; \`schema_truncated\` clears once describe returns the exact one. Otherwise fetch when the summary names a connector-specific sequence, unit, pagination rule, alias, or generic API convention relevant to the task. A read-only call whose compact schema is complete and unambiguous may proceed without fetching an otherwise irrelevant guide. Connector guides do not replace the shared Connecta usage guide and never apply to another deployment implicitly.
47
43
  `;
48
44
 
45
+ /** Shared Connecta routing guidance, byte-identical across deployments. */
46
+ export const USAGE_SKILL = USAGE_SKILL_BASE + CONNECTOR_GUIDES_SECTION;
47
+
49
48
  /** The always-loaded MCP `instructions` string. */
50
49
  export function instructionsFor(): string {
51
50
  return CONNECTA_INSTRUCTIONS;
@@ -58,10 +57,14 @@ export function hasConnectorGuides(connectors: readonly Connector[]): boolean {
58
57
  );
59
58
  }
60
59
 
61
- /** The built-in usage guide, plus the guides section when there is one to point at. */
62
- function usageSkill(connectors: readonly Connector[]): string {
63
- if (!hasConnectorGuides(connectors)) return USAGE_SKILL;
64
- return USAGE_SKILL + CONNECTOR_GUIDES_SECTION;
60
+ /**
61
+ * The built-in usage guide is byte-identical across deployments, so an agent
62
+ * that has read it once in a task never needs an equivalent deployment-local
63
+ * copy. Guide-free deployments still pay no fixed tool-description cost: the
64
+ * conditional notes in meta-tools.ts remain absent.
65
+ */
66
+ function usageSkill(_connectors: readonly Connector[]): string {
67
+ return USAGE_SKILL;
65
68
  }
66
69
 
67
70
  const AVAILABLE_SKILLS = [
@@ -90,7 +93,8 @@ export function connectorSkillName(connectorId: string): string {
90
93
  /** The connector's guide, or undefined when it declares none (or a blank one). */
91
94
  export function connectorGuide(connector: Connector): string | undefined {
92
95
  const guide = connector.usageGuide;
93
- return guide && guide.trim() !== "" ? guide : undefined;
96
+ const content = typeof guide === "string" ? guide : guide?.content;
97
+ return content && content.trim() !== "" ? content : undefined;
94
98
  }
95
99
 
96
100
  const SUMMARY_LENGTH = 120;
@@ -124,8 +128,17 @@ function withoutFrontmatter(lines: string[]): string[] {
124
128
  * the connector's own description when the guide opens with nothing but
125
129
  * markup.
126
130
  */
131
+ function boundedSummary(summary: string): string | undefined {
132
+ const line = summary.replace(/\s+/g, " ").trim();
133
+ if (line === "") return undefined;
134
+ return line.length <= SUMMARY_LENGTH
135
+ ? line
136
+ : `${line.slice(0, SUMMARY_LENGTH - 1).trimEnd()}…`;
137
+ }
138
+
127
139
  function summarizeGuide(connector: Connector, guide: string): string {
128
140
  let inFence = false;
141
+ let headingFallback: string | undefined;
129
142
  for (const raw of withoutFrontmatter(guide.split("\n"))) {
130
143
  if (FENCE_RE.test(raw)) {
131
144
  inFence = !inFence;
@@ -133,6 +146,7 @@ function summarizeGuide(connector: Connector, guide: string): string {
133
146
  }
134
147
  if (inFence) continue;
135
148
  if (raw.trim() === "" || NOT_SUMMARY_RE.test(raw)) continue;
149
+ const heading = /^\s*#{1,6}/.test(raw);
136
150
  const line = raw
137
151
  // `\s*` (not `\s+`) so a bare `#` strips to nothing and is skipped, and
138
152
  // an unspaced `#Heading` is still read as a heading.
@@ -141,11 +155,37 @@ function summarizeGuide(connector: Connector, guide: string): string {
141
155
  .replace(/\s+/g, " ")
142
156
  .trim();
143
157
  if (line === "") continue;
144
- return line.length <= SUMMARY_LENGTH
145
- ? line
146
- : `${line.slice(0, SUMMARY_LENGTH - 1).trimEnd()}…`;
158
+ if (heading) {
159
+ headingFallback ??= boundedSummary(line);
160
+ continue;
161
+ }
162
+ return boundedSummary(line) ?? line;
147
163
  }
148
- return connector.description ?? `Usage guide for "${connector.id}".`;
164
+ if (headingFallback) return headingFallback;
165
+ const fallback = connector.description ?? `Usage guide for "${connector.id}".`;
166
+ return boundedSummary(fallback) ?? `Usage guide for "${connector.id}".`;
167
+ }
168
+
169
+ /** Bounded, decision-useful discovery summary for a connector guide. */
170
+ export function connectorGuideSummary(
171
+ connector: Connector,
172
+ ): string | undefined {
173
+ const guide = connectorGuide(connector);
174
+ if (!guide) return undefined;
175
+ const configured =
176
+ typeof connector.usageGuide === "object"
177
+ ? boundedSummary(connector.usageGuide.summary ?? "")
178
+ : undefined;
179
+ return configured ?? summarizeGuide(connector, guide);
180
+ }
181
+
182
+ /** Whether correct use always depends on conventions outside the tool schema. */
183
+ export function connectorGuideRequired(connector: Connector): boolean {
184
+ return (
185
+ connectorGuide(connector) !== undefined &&
186
+ typeof connector.usageGuide === "object" &&
187
+ connector.usageGuide.required === true
188
+ );
149
189
  }
150
190
 
151
191
  export interface SkillListing {
@@ -164,11 +204,13 @@ export function listSkills(connectors: readonly Connector[]): SkillListing[] {
164
204
  description: skill.description,
165
205
  }));
166
206
  for (const connector of connectors) {
167
- const guide = connectorGuide(connector);
168
- if (!guide) continue;
207
+ // Undefined here means "no guide" and nothing else: a connector that has
208
+ // one always summarizes to a non-empty line, configured or derived.
209
+ const summary = connectorGuideSummary(connector);
210
+ if (!summary) continue;
169
211
  listing.push({
170
212
  name: connectorSkillName(connector.id),
171
- description: summarizeGuide(connector, guide),
213
+ description: summary,
172
214
  });
173
215
  }
174
216
  return listing;
package/src/types.ts CHANGED
@@ -212,13 +212,17 @@ export interface Connector {
212
212
  */
213
213
  callAdmission?: ConnectorCallAdmissionPolicy;
214
214
  /**
215
- * Optional agent-facing usage guide (markdown) for this connector preferred
216
- * tools, address quirks, pagination conventions, rate-limit etiquette, good
217
- * query patterns. Listed by the `skills` meta-tool as `connector:<id>` and
218
- * returned verbatim by `skills({ name: "connector:<id>" })`. Keep it concise
219
- * and imperative; it is read by agents, not operators.
215
+ * Optional agent-facing usage guide for this connector. A string preserves
216
+ * the original markdown-only contract. The structured form can add a short
217
+ * discovery summary and require review when even a complete compact schema
218
+ * cannot describe correct use (for example a generic API wrapper or a
219
+ * cross-operation sequencing rule).
220
+ *
221
+ * Listed by `skills` as `connector:<id>` and returned verbatim by
222
+ * `skills({ name: "connector:<id>" })`. The guide remains deployment-owned
223
+ * configuration; no runtime registration or shared mutable copy exists.
220
224
  */
221
- usageGuide?: string;
225
+ usageGuide?: string | ConnectorUsageGuide;
222
226
  /** Optional operator-managed credential slot rendered on /credentials. */
223
227
  credential?: ConnectorCredentialConfig;
224
228
  /** Optional server-side check used by /credentials' Test action. */
@@ -309,6 +313,23 @@ export interface Connector {
309
313
  ): Promise<Response | null>;
310
314
  }
311
315
 
316
+ export interface ConnectorUsageGuide {
317
+ /** Markdown returned verbatim by `skills({ name: "connector:<id>" })`. */
318
+ content: string;
319
+ /**
320
+ * Bounded discovery hint describing the conventions the guide covers. When
321
+ * omitted, Connecta derives a summary from the guide's first meaningful line.
322
+ */
323
+ summary?: string;
324
+ /**
325
+ * Require review before every operation on this connector. Reserve this for
326
+ * cases whose correct arguments or sequence cannot be expressed by the
327
+ * downstream tool schema; mutations and truncated schemas are required
328
+ * automatically and do not need this flag.
329
+ */
330
+ required?: boolean;
331
+ }
332
+
312
333
  /** Result of one sandboxed code execution. */
313
334
  export interface ExecuteResult {
314
335
  result: unknown;
package/src/version.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export const CONNECTA_VERSION = "0.12.1";
7
+ export const CONNECTA_VERSION = "0.13.0";
@@ -12,7 +12,7 @@
12
12
  "typecheck": "tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@zackbart/connecta": "0.12.1",
15
+ "@zackbart/connecta": "0.13.0",
16
16
  "quickjs-emscripten": "0.32.0"
17
17
  },
18
18
  "devDependencies": {