@finalai/final-agent-provider 0.1.3 → 0.1.4
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
|
@@ -66,6 +66,75 @@ other hosted connection. `binding`
|
|
|
66
66
|
selects another name. Existing explicit `url` calls remain static and compatible;
|
|
67
67
|
they always point at that URL. There is no Final-specific compiler rewrite.
|
|
68
68
|
|
|
69
|
+
## Connection tool policy
|
|
70
|
+
|
|
71
|
+
`tools.allow`, `tools.deny` and `tools.approval` keys are tool names or `*`
|
|
72
|
+
patterns, so a definition can scope a connection whose tool list it does not know:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
export default defineFinalConnection({
|
|
76
|
+
tools: {
|
|
77
|
+
allow: ['github.*', 'list_goals'],
|
|
78
|
+
deny: ['github.delete_repo'],
|
|
79
|
+
approval: { 'github.delete_*': always() },
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`*` matches any run of characters; everything else matches literally. `deny` wins
|
|
85
|
+
over `allow`. The most specific key governs a tool: an exact name, else the matching
|
|
86
|
+
pattern with the most literal characters, with ties resolved toward `ask`. Hosts
|
|
87
|
+
enforce this through `isToolExposed` and `toolApprovalOf` from
|
|
88
|
+
`@finalai/agent-provider`, and look up a tool's input-approval predicate under the
|
|
89
|
+
key `resolveToolApprovalKey` returns.
|
|
90
|
+
|
|
91
|
+
## Loaded and searchable tools
|
|
92
|
+
|
|
93
|
+
A connection that can expose many tools, such as Final's with every service the
|
|
94
|
+
person has connected, can name the ones the harness should list up front:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
export default defineFinalConnection({
|
|
98
|
+
tools: { load: ['list_goals', 'get_goal', 'draft_goal', 'notify_user'] },
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
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.
|
|
111
|
+
|
|
112
|
+
## Selecting tools by annotation
|
|
113
|
+
|
|
114
|
+
`tools.allow` and `tools.deny` entries can be MCP annotation selectors as well as
|
|
115
|
+
tool names, so a definition can scope tools it cannot name in advance:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
export default defineFinalConnection({
|
|
119
|
+
tools: {
|
|
120
|
+
allow: ['list_goals', 'draft_goal', { readOnlyHint: true }],
|
|
121
|
+
deny: [{ destructiveHint: true, readOnlyHint: false }],
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
A selector matches when every hint it sets equals the tool's hint, reading hints the
|
|
127
|
+
tool omits as the MCP spec's defaults (not read-only, destructive, not idempotent,
|
|
128
|
+
open world). The annotations come from the connection's server, so select on them
|
|
129
|
+
only for servers trusted to classify their own tools.
|
|
130
|
+
|
|
131
|
+
Selectors lower to `allowAnnotations` (each with the connection default approval and
|
|
132
|
+
input predicate) and `denyAnnotations`. A host exposes a tool when nothing in `deny`
|
|
133
|
+
or `denyAnnotations` matches it and either an `approvals` key (name or pattern)
|
|
134
|
+
governs it, `approvals` is null, or `toolAnnotationRuleFor` finds a rule; a tool an
|
|
135
|
+
`approvals` key governs keeps that approval, otherwise it runs under the rule's. `tools.approval` overrides apply only to
|
|
136
|
+
named tools.
|
|
137
|
+
|
|
69
138
|
## Resources and provider packages
|
|
70
139
|
|
|
71
140
|
`HostedBindingsIface` is the shared `@finalai/agent-provider` contract. Hosting
|
|
@@ -34,7 +34,7 @@ const deviceEndpoint = {
|
|
|
34
34
|
};
|
|
35
35
|
const resolvedManifest = () => ({
|
|
36
36
|
version: MANIFEST_VERSION,
|
|
37
|
-
identity: { name: "Release Scout", description: null
|
|
37
|
+
identity: { name: "Release Scout", description: null },
|
|
38
38
|
harness: {
|
|
39
39
|
harness: packageRef("@finalai/final-agent-provider/harnesses/serverless-pi"),
|
|
40
40
|
config: {}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/testing/harness.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n BaseCapability,\n CredentialRoute,\n credentials,\n jsonObjectSchema,\n MANIFEST_VERSION,\n packageRef,\n ToolApproval,\n type OpenHarnessSessionArgsIface,\n type ResolvedAgentManifestIface,\n type SandboxTargetEndpointIface,\n} from '@finalai/agent-provider';\n\n// Shared fixtures for the harness tests (no module mocks: fakes go in through\n// each factory's fetch/now/newId seams).\n\nexport const SESSION_ID = '0192f7a0-0000-7000-8000-000000000001';\nexport const HARNESS_SESSION_ID = '0192f7a0-0000-7000-8000-0000000000aa';\nexport const EXPIRES_AT = '2026-10-10T00:15:00.000Z';\n\nexport const computerEndpoint: SandboxTargetEndpointIface = {\n target: 'computer',\n bindingId: '0192f7a0-0000-7000-8000-0000000000c1',\n capabilities: ['shell', 'files', 'process'],\n rpc: { url: 'wss://agent-session.test/sandboxes/b/c1', token: 'rpc-c1', expiresAt: EXPIRES_AT },\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/c1/mcp',\n token: 'mcp-c1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const deviceEndpoint: SandboxTargetEndpointIface = {\n target: 'device',\n bindingId: '0192f7a0-0000-7000-8000-0000000000d1',\n capabilities: ['computerUse'],\n rpc: null,\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/d1/mcp',\n token: 'mcp-d1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const resolvedManifest = (): ResolvedAgentManifestIface => ({\n version: MANIFEST_VERSION,\n identity: { name: 'Release Scout', description: null
|
|
5
|
-
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAKA,MAAM,aAAa;AACnB,MAAM,qBAAqB;AAC3B,MAAM,aAAa;AAEnB,MAAM,mBAA+C;AAAA,EAC1D,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc,CAAC,SAAS,SAAS,SAAS;AAAA,EAC1C,KAAK,EAAE,KAAK,2CAA2C,OAAO,UAAU,WAAW,WAAW;AAAA,EAC9F,KAAK;AAAA,IACH,KAAK;AAAA,IACL,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AACF;AAEO,MAAM,iBAA6C;AAAA,EACxD,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc,CAAC,aAAa;AAAA,EAC5B,KAAK;AAAA,EACL,KAAK;AAAA,IACH,KAAK;AAAA,IACL,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AACF;AAEO,MAAM,mBAAmB,OAAmC;AAAA,EACjE,SAAS;AAAA,EACT,UAAU,EAAE,MAAM,iBAAiB,aAAa,
|
|
4
|
+
"sourcesContent": ["import {\n BaseCapability,\n CredentialRoute,\n credentials,\n jsonObjectSchema,\n MANIFEST_VERSION,\n packageRef,\n ToolApproval,\n type OpenHarnessSessionArgsIface,\n type ResolvedAgentManifestIface,\n type SandboxTargetEndpointIface,\n} from '@finalai/agent-provider';\n\n// Shared fixtures for the harness tests (no module mocks: fakes go in through\n// each factory's fetch/now/newId seams).\n\nexport const SESSION_ID = '0192f7a0-0000-7000-8000-000000000001';\nexport const HARNESS_SESSION_ID = '0192f7a0-0000-7000-8000-0000000000aa';\nexport const EXPIRES_AT = '2026-10-10T00:15:00.000Z';\n\nexport const computerEndpoint: SandboxTargetEndpointIface = {\n target: 'computer',\n bindingId: '0192f7a0-0000-7000-8000-0000000000c1',\n capabilities: ['shell', 'files', 'process'],\n rpc: { url: 'wss://agent-session.test/sandboxes/b/c1', token: 'rpc-c1', expiresAt: EXPIRES_AT },\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/c1/mcp',\n token: 'mcp-c1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const deviceEndpoint: SandboxTargetEndpointIface = {\n target: 'device',\n bindingId: '0192f7a0-0000-7000-8000-0000000000d1',\n capabilities: ['computerUse'],\n rpc: null,\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/d1/mcp',\n token: 'mcp-d1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const resolvedManifest = (): ResolvedAgentManifestIface => ({\n version: MANIFEST_VERSION,\n identity: { name: 'Release Scout', description: null },\n harness: {\n harness: packageRef('@finalai/final-agent-provider/harnesses/serverless-pi'),\n config: {},\n },\n mcpServers: [],\n sandboxes: {},\n tools: {\n base: {\n shell: { target: 'computer' },\n files: { target: 'computer' },\n computerUse: { target: 'device' },\n },\n },\n secrets: [],\n toolPolicy: {\n shell: ToolApproval.Ask,\n 'files.write': ToolApproval.Ask,\n create_issue: ToolApproval.Allow,\n },\n channels: [],\n hooks: [],\n schedules: [],\n bundle: null,\n});\n\nexport const openArgs = (\n config: unknown,\n secrets: Record<string, string> = {},\n): OpenHarnessSessionArgsIface => ({\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n session: {\n sessionId: SESSION_ID,\n organizationId: '0192f7a0-0000-7000-8000-0000000000o1',\n definitionId: '0192f7a0-0000-7000-8000-0000000000e1',\n revisionId: '0192f7a0-0000-7000-8000-0000000000r1',\n sessionServiceUrl: 'https://agent-session.test',\n },\n config: {\n credentials: credentials.chain({\n payer: 'organization',\n tryInOrder: [credentials.apiKey({ owner: 'organization' }), credentials.platform()],\n }),\n ...jsonObjectSchema.parse(config),\n },\n manifest: resolvedManifest(),\n mcpServers: [],\n baseTools: {\n [BaseCapability.Shell]: computerEndpoint,\n [BaseCapability.Files]: computerEndpoint,\n [BaseCapability.ComputerUse]: deviceEndpoint,\n },\n sandboxes: { computer: computerEndpoint, device: deviceEndpoint },\n credentials: {\n brokerUrl: 'https://agent-session.test/internal/runtime/broker',\n grants: [\n { route: CredentialRoute.Model, token: 'grant-model', expiresAt: EXPIRES_AT },\n { route: CredentialRoute.Mcp, token: 'grant-mcp', expiresAt: EXPIRES_AT },\n ],\n atOpen: null,\n refresh: {\n url: 'https://agent-session.test/internal/runtime/broker/refresh',\n token: 'grant-model',\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n expiresAt: EXPIRES_AT,\n },\n },\n secrets: { get: async (name) => secrets[name] ?? null },\n trace: {\n traceparent: '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01',\n tracestate: null,\n },\n});\n\n// Monotonic ids so assertions can name them.\nexport const idSequence = (prefix: string): (() => string) => {\n let next = 0;\n return () => {\n next += 1;\n return `${prefix}-7000-8000-${String(next).padStart(12, '0')}`;\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finalai/final-agent-provider",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Final's provider package: serverless, remote and local harnesses; the computer and device sandboxes; the messaging, schedule and event channels.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -213,14 +213,14 @@
|
|
|
213
213
|
},
|
|
214
214
|
"dependencies": {
|
|
215
215
|
"@agentclientprotocol/sdk": "1.8.0",
|
|
216
|
-
"@finalai/acp-session": "0.1.
|
|
217
|
-
"@finalai/agent-protocol": "0.1.
|
|
218
|
-
"@finalai/agent-provider": "0.1.
|
|
219
|
-
"@finalai/computers": "0.1.
|
|
220
|
-
"@finalai/websockets": "0.1.
|
|
216
|
+
"@finalai/acp-session": "0.1.4",
|
|
217
|
+
"@finalai/agent-protocol": "0.1.4",
|
|
218
|
+
"@finalai/agent-provider": "0.1.4",
|
|
219
|
+
"@finalai/computers": "0.1.4",
|
|
220
|
+
"@finalai/websockets": "0.1.4",
|
|
221
221
|
"ws": "^8.21.3",
|
|
222
222
|
"zod": "4.6.5",
|
|
223
|
-
"@finalai/agent-definition": "0.1.
|
|
223
|
+
"@finalai/agent-definition": "0.1.4"
|
|
224
224
|
},
|
|
225
225
|
"engines": {
|
|
226
226
|
"node": ">=26"
|