@finalai/agent-definition 0.1.4 → 0.1.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.
package/HOSTING.md CHANGED
@@ -21,6 +21,24 @@ Neither rewrites authored URLs. A GitHub-backed definition uses remote source;
21
21
  push edits before explicitly publishing a ref. Caller API keys never become agent
22
22
  credentials merely because they were used to publish.
23
23
 
24
+ ## Hosted model resolution (SDK 0.2.0)
25
+
26
+ Hosted Final, Pi, Codex and Claude configurations accept string model references.
27
+ `serverless*ConfigSchema.parse(...).model` can be undefined: the host must choose
28
+ its catalog default, resolve aliases and validate availability before dispatch.
29
+ The host owns current candidates, runtime capabilities and dated prices, and
30
+ advertises picker choices through its harness descriptions. Compilation remains
31
+ offline and checks reference syntax.
32
+
33
+ SDK 0.2.0 removes `@finalai/agents/models` and
34
+ `@finalai/final-agent-provider/harnesses/models`, including their model arrays,
35
+ defaults, model-ID unions and pricing helpers. Migrate callers to string model
36
+ references and host-owned discovery, metadata and pricing.
37
+
38
+ Publish the SDK release before upgrading host dependencies. Ship the host's
39
+ catalog/default implementation together with its SDK dependency upgrade; a host
40
+ that only changes the dependency will lose the old default and catalog APIs.
41
+
24
42
  ## Hosted connections
25
43
 
26
44
  ```ts
@@ -99,15 +117,37 @@ export default defineFinalConnection({
99
117
  });
100
118
  ```
101
119
 
102
- Without `load`, the harness lists every exposed tool, as before. With it, the host
103
- lists only the loaded tools and must keep every other exposed tool reachable: it
104
- serves a search over the connection's remaining exposed tools (name, description,
105
- input schema) and a call that runs a found tool by its real name, with the same
106
- exposure and approval checks as a direct call. A host may instead add a found tool
107
- to the list and send `notifications/tools/list_changed`; harnesses that ignore that
108
- notification still need the call path. `load: []` leaves every tool to search.
109
- Entries are tool names or `*` patterns. `isToolLoaded` from `@finalai/agent-provider`
110
- applies the rule after exposure.
120
+ With `load`, the host lists only the loaded tools and must keep every other exposed
121
+ tool reachable: it serves a search over the connection's remaining exposed tools
122
+ (name, description, input schema) and a call that runs a found tool by its real
123
+ name, with the same exposure and approval checks as a direct call. A host may
124
+ instead add a found tool to the list and send `notifications/tools/list_changed`;
125
+ harnesses that ignore that notification still need the call path. `load: []`
126
+ leaves every tool to search. Entries are tool names or `*` patterns.
127
+ `isToolLoaded` from `@finalai/agent-provider` applies the rule after exposure.
128
+
129
+ Without `load`, the harness lists the connection's exposed tools except:
130
+
131
+ - **Connector tools.** A server can label a tool with the connector it belongs to
132
+ in the tool's `_meta`:
133
+ `{ "ai.final/connector": { "namespace": "salesforce", "name": "Salesforce" } }`.
134
+ The namespace identifies the connector (unique within the server's tools); the
135
+ name is for display, and two connectors may share one. Final's server labels
136
+ every connector tool with the namespace and name of the install it comes from.
137
+ The host never lists labelled tools up front. Its search tool names each
138
+ connector and how many tools it has, so the agent knows what is connected
139
+ without any of those definitions in its context, and searches for the tools it
140
+ needs. A `load` entry that names a labelled tool still lists it.
141
+ - **Tools past a size limit.** When a connection exposes more unlabelled tools
142
+ than the host lists directly (100 in Final's host), those are searched too.
143
+
144
+ A harness that declares `supports.deferredToolSearch` defers and searches tools
145
+ itself, so the host lists every exposed tool to it and serves no search.
146
+
147
+ A host's search should name the connectors it covers and accept a connector's
148
+ namespace to narrow to. Once a host has listed its search and call tools, it keeps answering them for
149
+ that harness even if the connection stops hiding tools, unless the connection
150
+ then lists its own tool by one of those names.
111
151
 
112
152
  ## Selecting tools by annotation
113
153
 
@@ -68,7 +68,7 @@ var SHARED_SCHEMAS = {
68
68
  [SCHEMA_IDS.modelPicker]: {
69
69
  $id: SCHEMA_IDS.modelPicker,
70
70
  title: "Model",
71
- // The harness supplies the enum: { $ref: model-picker, enum: [...] }.
71
+ // The harness or hosting platform supplies reference constraints and picker choices.
72
72
  type: "string",
73
73
  "x-final-widget": "model-picker"
74
74
  },
@@ -263,7 +263,8 @@ var harnessDescriptionSchema = object({
263
263
  nativeToolPolicy: boolean().optional(),
264
264
  // Defers and searches MCP tools itself (a harness-native tool search): the
265
265
  // host lists every exposed tool, ignoring connections' `tools.load`, and
266
- // adds no search of its own. Absent: the host applies `load` and serves search.
266
+ // adds no search of its own. Absent: the host lists what `load` (or, without
267
+ // it, HOSTING.md's defaults) leaves listed and serves search for the rest.
267
268
  deferredToolSearch: boolean().optional()
268
269
  }),
269
270
  promptWhileRunning: nativeEnum(PromptWhileRunning).default(DEFAULT_PROMPT_WHILE_RUNNING),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  harnessDescriptionSchema
3
- } from "./chunk-RIEMTCTV.ts";
3
+ } from "./chunk-5PWY25HA.ts";
4
4
  import {
5
5
  bundleRef
6
6
  } from "./chunk-APU2VKLW.ts";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  completeHarnessDescription,
3
3
  defineHarness
4
- } from "../../chunk-Z5TO7RSJ.ts";
5
- import "../../chunk-RIEMTCTV.ts";
4
+ } from "../../chunk-RSWGFPNZ.ts";
5
+ import "../../chunk-5PWY25HA.ts";
6
6
  import "../../chunk-APU2VKLW.ts";
7
7
  import "../../chunk-GCFSHHH2.ts";
8
8
  import "../../chunk-MSE7X5YG.ts";
@@ -2,7 +2,7 @@ import "../../chunk-RMIQJHSL.ts";
2
2
  import {
3
3
  completeHarnessDescription,
4
4
  defineHarness
5
- } from "../../chunk-Z5TO7RSJ.ts";
5
+ } from "../../chunk-RSWGFPNZ.ts";
6
6
  import {
7
7
  HookEvent,
8
8
  defineHook
@@ -15,11 +15,11 @@ import {
15
15
  defineSandbox,
16
16
  defineSandboxProvider,
17
17
  harnessHost
18
- } from "../../chunk-IZGOMT7K.ts";
18
+ } from "../../chunk-B5RJDCXZ.ts";
19
19
  import "../../chunk-4E5HECVD.ts";
20
20
  import {
21
21
  SandboxWire
22
- } from "../../chunk-RIEMTCTV.ts";
22
+ } from "../../chunk-5PWY25HA.ts";
23
23
  import {
24
24
  defineSchedule
25
25
  } from "../../chunk-JGQ2KAN7.ts";
@@ -3,11 +3,11 @@ import {
3
3
  defineSandbox,
4
4
  defineSandboxProvider,
5
5
  harnessHost
6
- } from "../../chunk-IZGOMT7K.ts";
6
+ } from "../../chunk-B5RJDCXZ.ts";
7
7
  import "../../chunk-4E5HECVD.ts";
8
8
  import {
9
9
  SandboxWire
10
- } from "../../chunk-RIEMTCTV.ts";
10
+ } from "../../chunk-5PWY25HA.ts";
11
11
  import "../../chunk-APU2VKLW.ts";
12
12
  import "../../chunk-GCFSHHH2.ts";
13
13
  import "../../chunk-MSE7X5YG.ts";
@@ -3,7 +3,7 @@ import {
3
3
  SHARED_SCHEMAS,
4
4
  deliveredHarnessConfig,
5
5
  referencedSharedSchemas
6
- } from "../chunk-RIEMTCTV.ts";
6
+ } from "../chunk-5PWY25HA.ts";
7
7
  import {
8
8
  BaseCapability,
9
9
  formatProviderRef
@@ -15,7 +15,7 @@ import "../chunk-RMIQJHSL.ts";
15
15
  import {
16
16
  completeHarnessDescription,
17
17
  defineHarness
18
- } from "../chunk-Z5TO7RSJ.ts";
18
+ } from "../chunk-RSWGFPNZ.ts";
19
19
  import {
20
20
  HookEvent,
21
21
  defineHook
@@ -28,11 +28,11 @@ import {
28
28
  defineSandbox,
29
29
  defineSandboxProvider,
30
30
  harnessHost
31
- } from "../chunk-IZGOMT7K.ts";
31
+ } from "../chunk-B5RJDCXZ.ts";
32
32
  import "../chunk-4E5HECVD.ts";
33
33
  import {
34
34
  SandboxWire
35
- } from "../chunk-RIEMTCTV.ts";
35
+ } from "../chunk-5PWY25HA.ts";
36
36
  import {
37
37
  defineSchedule
38
38
  } from "../chunk-JGQ2KAN7.ts";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/authoring/connections.ts"],
4
- "sourcesContent": ["import type { ApprovalPolicyIface } from \"./approval.mjs\";\nimport { AuthoredKind, stamp } from \"./brand.mjs\";\nimport { jsonObjectSchema, mcpAuthSchema, requireHostedBinding } from '@finalai/agent-provider';\nimport * as z from 'zod';\nimport { defineDynamic, type DynamicSentinelIface } from \"./dynamic.mjs\";\n\n// An MCP connection. Secrets are references by\n// name: the MCP host injects them, so they never reach the harness. Final's\n// own MCP server is an ordinary connection with `auth: { kind: 'final-session' }`.\n\nexport type McpConnectionAuthIface =\n // Sent as `Authorization: Bearer <secret>` when headerName is null.\n | { readonly secretKey: string; readonly headerName: string | null }\n | { readonly kind: 'final-session' };\n\n// Selects tools by the MCP annotations their server reports, reading omitted\n// hints as the spec's defaults: `{ readOnlyHint: true }` matches only tools\n// the server marks read-only. Use with servers you trust to classify tools.\nexport interface McpToolAnnotationSelectorIface {\n readonly readOnlyHint?: boolean;\n readonly destructiveHint?: boolean;\n readonly idempotentHint?: boolean;\n readonly openWorldHint?: boolean;\n}\n\nexport type McpToolSelector = string | McpToolAnnotationSelectorIface;\n\n// Entries and keys are tool names or `*` patterns (`github.*`), and allow and\n// deny entries may also be annotation selectors; the most specific matching\n// key governs a tool.\nexport interface McpConnectionToolsIface {\n // Only these tools are exposed; omit to expose every tool the server lists.\n // Annotation-selected tools run under the connection's default approval.\n readonly allow?: readonly McpToolSelector[];\n // These tools are hidden, whatever `allow` says.\n readonly deny?: readonly McpToolSelector[];\n // Per-tool approval; tools not listed use the connection's `approval`.\n readonly approval?: Readonly<Record<string, ApprovalPolicyIface<never>>>;\n // Exposed tools (names or `*` patterns) the harness lists up front; the rest\n // stay reachable through the host's tool search. Omit to list every exposed tool.\n readonly load?: readonly string[];\n}\n\nexport interface McpClientConnectionDefinitionIface {\n readonly url: string;\n readonly description?: string;\n readonly auth?: McpConnectionAuthIface;\n readonly headers?: Readonly<Record<string, string>>;\n readonly tools?: McpConnectionToolsIface;\n // Default approval for every tool of this connection.\n readonly approval?: ApprovalPolicyIface<never>;\n readonly protocolVersionDiscovery?: boolean;\n readonly instanceKey?: string;\n}\n\nexport const defineMcpClientConnection = <TConnection extends McpClientConnectionDefinitionIface>(\n definition: TConnection,\n): TConnection => stamp({ ...definition }, AuthoredKind.Connection);\n\nexport interface HostedConnectionDefinitionIface extends Omit<\n McpClientConnectionDefinitionIface,\n 'url' | 'auth' | 'headers' | 'protocolVersionDiscovery' | 'instanceKey'\n> {\n readonly binding: string;\n}\n\nconst hostedConnectionSchema = z.strictObject({\n url: z.string().url(),\n auth: mcpAuthSchema.nullable().optional(),\n headers: z.record(z.string(), z.string()).optional(),\n});\n\n// Built-in and third-party bindings use the ordinary dynamic connection path.\nexport const defineHostedConnection = (\n definition: HostedConnectionDefinitionIface,\n): DynamicSentinelIface<McpClientConnectionDefinitionIface> => {\n const { binding, description, tools, approval } = definition;\n if (binding.trim().length === 0) throw new Error('Hosted connection binding must not be empty');\n return defineDynamic({\n description: definition.description ?? `Hosted connection ${binding}`,\n preview: `Resolved by hosting from ${binding}`,\n requiredBindings: [\n { name: binding, schema: jsonObjectSchema.parse(z.toJSONSchema(hostedConnectionSchema)) },\n ],\n events: {\n 'session.started': async (_event, ctx) => {\n const value = await requireHostedBinding({ bindings: ctx.bindings, name: binding });\n const parsed = hostedConnectionSchema.safeParse(value);\n if (!parsed.success)\n throw new Error(`Hosted connection ${binding} has invalid configuration`);\n const { auth, ...transport } = parsed.data;\n return defineMcpClientConnection({\n ...transport,\n description,\n tools,\n approval,\n ...(auth == null ? {} : { auth }),\n });\n },\n },\n });\n};\n"],
5
- "mappings": "AACA,SAAS,cAAc,aAAa;AACpC,SAAS,kBAAkB,eAAe,4BAA4B;AACtE,YAAY,OAAO;AACnB,SAAS,qBAAgD;AAmDlD,MAAM,4BAA4B,CACvC,eACgB,MAAM,EAAE,GAAG,WAAW,GAAG,aAAa,UAAU;AASlE,MAAM,yBAAyB,EAAE,aAAa;AAAA,EAC5C,KAAK,EAAE,OAAO,EAAE,IAAI;AAAA,EACpB,MAAM,cAAc,SAAS,EAAE,SAAS;AAAA,EACxC,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AACrD,CAAC;AAGM,MAAM,yBAAyB,CACpC,eAC6D;AAC7D,QAAM,EAAE,SAAS,aAAa,OAAO,SAAS,IAAI;AAClD,MAAI,QAAQ,KAAK,EAAE,WAAW,EAAG,OAAM,IAAI,MAAM,6CAA6C;AAC9F,SAAO,cAAc;AAAA,IACnB,aAAa,WAAW,eAAe,qBAAqB,OAAO;AAAA,IACnE,SAAS,4BAA4B,OAAO;AAAA,IAC5C,kBAAkB;AAAA,MAChB,EAAE,MAAM,SAAS,QAAQ,iBAAiB,MAAM,EAAE,aAAa,sBAAsB,CAAC,EAAE;AAAA,IAC1F;AAAA,IACA,QAAQ;AAAA,MACN,mBAAmB,OAAO,QAAQ,QAAQ;AACxC,cAAM,QAAQ,MAAM,qBAAqB,EAAE,UAAU,IAAI,UAAU,MAAM,QAAQ,CAAC;AAClF,cAAM,SAAS,uBAAuB,UAAU,KAAK;AACrD,YAAI,CAAC,OAAO;AACV,gBAAM,IAAI,MAAM,qBAAqB,OAAO,4BAA4B;AAC1E,cAAM,EAAE,MAAM,GAAG,UAAU,IAAI,OAAO;AACtC,eAAO,0BAA0B;AAAA,UAC/B,GAAG;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA,GAAI,QAAQ,OAAO,CAAC,IAAI,EAAE,KAAK;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACH;",
4
+ "sourcesContent": ["import type { ApprovalPolicyIface } from \"./approval.mjs\";\nimport { AuthoredKind, stamp } from \"./brand.mjs\";\nimport { jsonObjectSchema, mcpAuthSchema, requireHostedBinding } from '@finalai/agent-provider';\nimport * as z from 'zod';\nimport { defineDynamic, type DynamicSentinelIface } from \"./dynamic.mjs\";\n\n// An MCP connection. Secrets are references by\n// name: the MCP host injects them, so they never reach the harness. Final's\n// own MCP server is an ordinary connection with `auth: { kind: 'final-session' }`.\n\nexport type McpConnectionAuthIface =\n // Sent as `Authorization: Bearer <secret>` when headerName is null.\n | { readonly secretKey: string; readonly headerName: string | null }\n | { readonly kind: 'final-session' };\n\n// Selects tools by the MCP annotations their server reports, reading omitted\n// hints as the spec's defaults: `{ readOnlyHint: true }` matches only tools\n// the server marks read-only. Use with servers you trust to classify tools.\nexport interface McpToolAnnotationSelectorIface {\n readonly readOnlyHint?: boolean;\n readonly destructiveHint?: boolean;\n readonly idempotentHint?: boolean;\n readonly openWorldHint?: boolean;\n}\n\nexport type McpToolSelector = string | McpToolAnnotationSelectorIface;\n\n// Entries and keys are tool names or `*` patterns (`github.*`), and allow and\n// deny entries may also be annotation selectors; the most specific matching\n// key governs a tool.\nexport interface McpConnectionToolsIface {\n // Only these tools are exposed; omit to expose every tool the server lists.\n // Annotation-selected tools run under the connection's default approval.\n readonly allow?: readonly McpToolSelector[];\n // These tools are hidden, whatever `allow` says.\n readonly deny?: readonly McpToolSelector[];\n // Per-tool approval; tools not listed use the connection's `approval`.\n readonly approval?: Readonly<Record<string, ApprovalPolicyIface<never>>>;\n // Exposed tools (names or `*` patterns) the harness lists up front; the rest\n // stay reachable through the host's tool search. Omitted, the harness lists\n // every exposed tool except connector tools and tools past the\n // host's size limit (HOSTING.md \"Loaded and searchable tools\").\n readonly load?: readonly string[];\n}\n\nexport interface McpClientConnectionDefinitionIface {\n readonly url: string;\n readonly description?: string;\n readonly auth?: McpConnectionAuthIface;\n readonly headers?: Readonly<Record<string, string>>;\n readonly tools?: McpConnectionToolsIface;\n // Default approval for every tool of this connection.\n readonly approval?: ApprovalPolicyIface<never>;\n readonly protocolVersionDiscovery?: boolean;\n readonly instanceKey?: string;\n}\n\nexport const defineMcpClientConnection = <TConnection extends McpClientConnectionDefinitionIface>(\n definition: TConnection,\n): TConnection => stamp({ ...definition }, AuthoredKind.Connection);\n\nexport interface HostedConnectionDefinitionIface extends Omit<\n McpClientConnectionDefinitionIface,\n 'url' | 'auth' | 'headers' | 'protocolVersionDiscovery' | 'instanceKey'\n> {\n readonly binding: string;\n}\n\nconst hostedConnectionSchema = z.strictObject({\n url: z.string().url(),\n auth: mcpAuthSchema.nullable().optional(),\n headers: z.record(z.string(), z.string()).optional(),\n});\n\n// Built-in and third-party bindings use the ordinary dynamic connection path.\nexport const defineHostedConnection = (\n definition: HostedConnectionDefinitionIface,\n): DynamicSentinelIface<McpClientConnectionDefinitionIface> => {\n const { binding, description, tools, approval } = definition;\n if (binding.trim().length === 0) throw new Error('Hosted connection binding must not be empty');\n return defineDynamic({\n description: definition.description ?? `Hosted connection ${binding}`,\n preview: `Resolved by hosting from ${binding}`,\n requiredBindings: [\n { name: binding, schema: jsonObjectSchema.parse(z.toJSONSchema(hostedConnectionSchema)) },\n ],\n events: {\n 'session.started': async (_event, ctx) => {\n const value = await requireHostedBinding({ bindings: ctx.bindings, name: binding });\n const parsed = hostedConnectionSchema.safeParse(value);\n if (!parsed.success)\n throw new Error(`Hosted connection ${binding} has invalid configuration`);\n const { auth, ...transport } = parsed.data;\n return defineMcpClientConnection({\n ...transport,\n description,\n tools,\n approval,\n ...(auth == null ? {} : { auth }),\n });\n },\n },\n });\n};\n"],
5
+ "mappings": "AACA,SAAS,cAAc,aAAa;AACpC,SAAS,kBAAkB,eAAe,4BAA4B;AACtE,YAAY,OAAO;AACnB,SAAS,qBAAgD;AAqDlD,MAAM,4BAA4B,CACvC,eACgB,MAAM,EAAE,GAAG,WAAW,GAAG,aAAa,UAAU;AASlE,MAAM,yBAAyB,EAAE,aAAa;AAAA,EAC5C,KAAK,EAAE,OAAO,EAAE,IAAI;AAAA,EACpB,MAAM,cAAc,SAAS,EAAE,SAAS;AAAA,EACxC,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AACrD,CAAC;AAGM,MAAM,yBAAyB,CACpC,eAC6D;AAC7D,QAAM,EAAE,SAAS,aAAa,OAAO,SAAS,IAAI;AAClD,MAAI,QAAQ,KAAK,EAAE,WAAW,EAAG,OAAM,IAAI,MAAM,6CAA6C;AAC9F,SAAO,cAAc;AAAA,IACnB,aAAa,WAAW,eAAe,qBAAqB,OAAO;AAAA,IACnE,SAAS,4BAA4B,OAAO;AAAA,IAC5C,kBAAkB;AAAA,MAChB,EAAE,MAAM,SAAS,QAAQ,iBAAiB,MAAM,EAAE,aAAa,sBAAsB,CAAC,EAAE;AAAA,IAC1F;AAAA,IACA,QAAQ;AAAA,MACN,mBAAmB,OAAO,QAAQ,QAAQ;AACxC,cAAM,QAAQ,MAAM,qBAAqB,EAAE,UAAU,IAAI,UAAU,MAAM,QAAQ,CAAC;AAClF,cAAM,SAAS,uBAAuB,UAAU,KAAK;AACrD,YAAI,CAAC,OAAO;AACV,gBAAM,IAAI,MAAM,qBAAqB,OAAO,4BAA4B;AAC1E,cAAM,EAAE,MAAM,GAAG,UAAU,IAAI,OAAO;AACtC,eAAO,0BAA0B;AAAA,UAC/B,GAAG;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA,GAAI,QAAQ,OAAO,CAAC,IAAI,EAAE,KAAK;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -7,7 +7,7 @@ export const computer = computerSetupGuide({
7
7
  ref: 'release-scout-dev',
8
8
  version: 'latest',
9
9
  repositories: [{ alias: 'app', repository: 'final/app', ref: 'main' }],
10
- variables: ['GITHUB_TOKEN', 'NPM_TOKEN'],
10
+ variables: ['NPM_TOKEN'],
11
11
  workspace: 'session',
12
12
  networkPolicy: 'allow-all',
13
13
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finalai/agent-definition",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "private": false,
5
5
  "description": "Provider-independent agent authoring, manifest schemas, directory compiler, and harness compatibility reports.",
6
6
  "license": "Apache-2.0",
@@ -76,7 +76,7 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@finalai/agent-protocol": "0.1.4",
79
- "@finalai/agent-provider": "0.1.4",
79
+ "@finalai/agent-provider": "0.1.6",
80
80
  "ajv": "^8.20.0",
81
81
  "ajv-formats": "^3.0.1",
82
82
  "croner": "^10.0.1",