@finalai/agents 0.11.0 → 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 (188) hide show
  1. package/HOSTING.md +334 -245
  2. package/README.md +214 -29
  3. package/dist/modules/agent-client/agent-input.d.mts +24 -0
  4. package/dist/modules/agent-client/agent-input.mjs +46 -0
  5. package/dist/modules/agent-client/agent-input.mjs.map +7 -0
  6. package/dist/modules/agent-client/channels.d.mts +128 -16
  7. package/dist/modules/agent-client/channels.mjs +216 -33
  8. package/dist/modules/agent-client/channels.mjs.map +2 -2
  9. package/dist/modules/agent-client/client.d.mts +91 -21
  10. package/dist/modules/agent-client/client.mjs +79 -24
  11. package/dist/modules/agent-client/client.mjs.map +2 -2
  12. package/dist/modules/agent-client/config-options.mjs +1 -2
  13. package/dist/modules/agent-client/config-options.mjs.map +2 -2
  14. package/dist/modules/agent-client/conversation-resources.d.mts +102 -0
  15. package/dist/modules/agent-client/conversation-resources.mjs +178 -0
  16. package/dist/modules/agent-client/conversation-resources.mjs.map +7 -0
  17. package/dist/modules/agent-client/conversations.d.mts +120 -38
  18. package/dist/modules/agent-client/conversations.mjs +386 -71
  19. package/dist/modules/agent-client/conversations.mjs.map +2 -2
  20. package/dist/modules/agent-client/defaults.d.mts +8 -0
  21. package/dist/modules/agent-client/defaults.mjs +77 -0
  22. package/dist/modules/agent-client/defaults.mjs.map +7 -0
  23. package/dist/modules/agent-client/errors.d.mts +22 -2
  24. package/dist/modules/agent-client/errors.mjs +19 -0
  25. package/dist/modules/agent-client/errors.mjs.map +2 -2
  26. package/dist/modules/agent-client/events.d.mts +62 -0
  27. package/dist/modules/agent-client/events.mjs +107 -0
  28. package/dist/modules/agent-client/events.mjs.map +7 -0
  29. package/dist/modules/agent-client/harnesses.d.mts +66 -0
  30. package/dist/modules/agent-client/harnesses.mjs +156 -0
  31. package/dist/modules/agent-client/harnesses.mjs.map +7 -0
  32. package/dist/modules/agent-client/http.d.mts +2 -1
  33. package/dist/modules/agent-client/http.mjs +21 -2
  34. package/dist/modules/agent-client/http.mjs.map +2 -2
  35. package/dist/modules/agent-client/index.d.mts +21 -6
  36. package/dist/modules/agent-client/index.mjs +26 -0
  37. package/dist/modules/agent-client/index.mjs.map +2 -2
  38. package/dist/modules/agent-client/integrations.d.mts +40 -0
  39. package/dist/modules/agent-client/integrations.mjs +92 -0
  40. package/dist/modules/agent-client/integrations.mjs.map +7 -0
  41. package/dist/modules/agent-client/local-host-protocol.d.mts +156 -0
  42. package/dist/modules/agent-client/local-host-protocol.mjs +258 -0
  43. package/dist/modules/agent-client/local-host-protocol.mjs.map +7 -0
  44. package/dist/modules/agent-client/local-host.d.mts +56 -0
  45. package/dist/modules/agent-client/local-host.mjs +200 -0
  46. package/dist/modules/agent-client/local-host.mjs.map +7 -0
  47. package/dist/modules/agent-client/oauth-clients.d.mts +36 -0
  48. package/dist/modules/agent-client/oauth-clients.mjs +67 -0
  49. package/dist/modules/agent-client/oauth-clients.mjs.map +7 -0
  50. package/dist/modules/agent-client/project-agents.d.mts +54 -0
  51. package/dist/modules/agent-client/project-agents.mjs +111 -0
  52. package/dist/modules/agent-client/project-agents.mjs.map +7 -0
  53. package/dist/modules/agent-client/project.d.mts +48 -0
  54. package/dist/modules/agent-client/project.mjs +66 -0
  55. package/dist/modules/agent-client/project.mjs.map +7 -0
  56. package/dist/modules/agent-client/projects.d.mts +61 -0
  57. package/dist/modules/agent-client/projects.mjs +145 -0
  58. package/dist/modules/agent-client/projects.mjs.map +7 -0
  59. package/dist/modules/agent-client/provide.d.mts +41 -0
  60. package/dist/modules/agent-client/provide.mjs +90 -0
  61. package/dist/modules/agent-client/provide.mjs.map +7 -0
  62. package/dist/modules/agent-client/publishers.d.mts +57 -0
  63. package/dist/modules/agent-client/publishers.mjs +109 -0
  64. package/dist/modules/agent-client/publishers.mjs.map +7 -0
  65. package/dist/modules/agent-client/requirements.d.mts +60 -0
  66. package/dist/modules/agent-client/requirements.mjs +83 -0
  67. package/dist/modules/agent-client/requirements.mjs.map +7 -0
  68. package/dist/modules/agent-client/sandbox-providers.d.mts +34 -0
  69. package/dist/modules/agent-client/sandbox-providers.mjs +75 -0
  70. package/dist/modules/agent-client/sandbox-providers.mjs.map +7 -0
  71. package/dist/modules/agent-client/sandbox-uri.d.mts +1 -1
  72. package/dist/modules/agent-client/sandbox-uri.mjs +4 -4
  73. package/dist/modules/agent-client/sandbox-uri.mjs.map +1 -1
  74. package/dist/modules/agent-client/sandboxes.d.mts +72 -0
  75. package/dist/modules/agent-client/sandboxes.mjs +138 -0
  76. package/dist/modules/agent-client/sandboxes.mjs.map +7 -0
  77. package/dist/modules/agent-client/schedules.d.mts +9 -0
  78. package/dist/modules/agent-client/schedules.mjs +17 -0
  79. package/dist/modules/agent-client/schedules.mjs.map +7 -0
  80. package/dist/modules/agent-client/sessions.d.mts +46 -8
  81. package/dist/modules/agent-client/sessions.mjs +91 -29
  82. package/dist/modules/agent-client/sessions.mjs.map +2 -2
  83. package/dist/modules/agent-client/start.d.mts +101 -0
  84. package/dist/modules/agent-client/start.mjs +260 -0
  85. package/dist/modules/agent-client/start.mjs.map +7 -0
  86. package/dist/modules/agent-client/test-fakes.d.mts +1 -0
  87. package/dist/modules/agent-client/test-fakes.mjs +3 -1
  88. package/dist/modules/agent-client/test-fakes.mjs.map +2 -2
  89. package/dist/modules/cli/agent-module.d.mts +39 -0
  90. package/dist/modules/cli/agent-module.mjs +89 -0
  91. package/dist/modules/cli/agent-module.mjs.map +7 -0
  92. package/dist/modules/cli/cli.d.mts +6 -6
  93. package/dist/modules/cli/cli.mjs +94 -120
  94. package/dist/modules/cli/cli.mjs.map +2 -2
  95. package/dist/modules/cli/conformance.d.mts +2 -6
  96. package/dist/modules/cli/conformance.mjs +5 -8
  97. package/dist/modules/cli/conformance.mjs.map +2 -2
  98. package/dist/modules/cli/main.mjs.map +1 -1
  99. package/dist/modules/cli/output.d.mts +0 -9
  100. package/dist/modules/cli/output.mjs +7 -85
  101. package/dist/modules/cli/output.mjs.map +2 -2
  102. package/dist/modules/harnesses.mjs.map +2 -2
  103. package/dist/modules/index.d.mts +0 -2
  104. package/dist/modules/index.mjs +0 -4
  105. package/dist/modules/index.mjs.map +2 -2
  106. package/dist/modules/integrations.d.mts +24 -0
  107. package/dist/modules/integrations.mjs +30 -0
  108. package/dist/modules/integrations.mjs.map +7 -0
  109. package/dist/modules/public.d.mts +10 -10
  110. package/dist/modules/public.mjs +29 -78
  111. package/dist/modules/public.mjs.map +2 -2
  112. package/dist/modules/sandboxes.d.mts +2 -0
  113. package/dist/modules/sandboxes.mjs +4 -0
  114. package/dist/modules/sandboxes.mjs.map +2 -2
  115. package/dist/modules/verify.d.mts +1 -0
  116. package/dist/modules/verify.mjs +2 -0
  117. package/dist/modules/verify.mjs.map +7 -0
  118. package/dist/modules/webhooks.d.mts +37 -0
  119. package/dist/modules/webhooks.mjs +100 -0
  120. package/dist/modules/webhooks.mjs.map +7 -0
  121. package/examples/release-scout/README.md +18 -10
  122. package/examples/release-scout/agent.ts +41 -0
  123. package/examples/release-scout/by-name.ts +43 -0
  124. package/examples/release-scout/db.ts +6 -0
  125. package/examples/release-scout/instructions.md +5 -0
  126. package/examples/release-scout/run-on-a-computer.ts +49 -0
  127. package/examples/release-scout/run.ts +38 -0
  128. package/package.json +37 -28
  129. package/dist/modules/agent-client/build.d.mts +0 -110
  130. package/dist/modules/agent-client/build.mjs +0 -213
  131. package/dist/modules/agent-client/build.mjs.map +0 -7
  132. package/dist/modules/authoring/final-channel.d.mts +0 -1
  133. package/dist/modules/authoring/final-channel.mjs +0 -2
  134. package/dist/modules/authoring/final-channel.mjs.map +0 -7
  135. package/dist/modules/authoring/index.d.mts +0 -1
  136. package/dist/modules/authoring/index.mjs +0 -2
  137. package/dist/modules/authoring/index.mjs.map +0 -7
  138. package/dist/modules/authoring/instructions.d.mts +0 -1
  139. package/dist/modules/authoring/instructions.mjs +0 -2
  140. package/dist/modules/authoring/instructions.mjs.map +0 -7
  141. package/dist/modules/authoring/providers.d.mts +0 -2
  142. package/dist/modules/authoring/providers.mjs +0 -1
  143. package/dist/modules/authoring/providers.mjs.map +0 -7
  144. package/dist/modules/cli/build.d.mts +0 -22
  145. package/dist/modules/cli/build.mjs +0 -77
  146. package/dist/modules/cli/build.mjs.map +0 -7
  147. package/dist/modules/cli/channel-install.d.mts +0 -12
  148. package/dist/modules/cli/channel-install.mjs +0 -25
  149. package/dist/modules/cli/channel-install.mjs.map +0 -7
  150. package/dist/modules/cli/channel-socket.d.mts +0 -9
  151. package/dist/modules/cli/channel-socket.mjs +0 -114
  152. package/dist/modules/cli/channel-socket.mjs.map +0 -7
  153. package/dist/modules/cli/dev.d.mts +0 -26
  154. package/dist/modules/cli/dev.mjs +0 -311
  155. package/dist/modules/cli/dev.mjs.map +0 -7
  156. package/dist/modules/cli/files.d.mts +0 -18
  157. package/dist/modules/cli/files.mjs +0 -66
  158. package/dist/modules/cli/files.mjs.map +0 -7
  159. package/dist/modules/cli/harness-descriptions.d.mts +0 -20
  160. package/dist/modules/cli/harness-descriptions.mjs +0 -70
  161. package/dist/modules/cli/harness-descriptions.mjs.map +0 -7
  162. package/dist/modules/cli/publish.d.mts +0 -15
  163. package/dist/modules/cli/publish.mjs +0 -92
  164. package/dist/modules/cli/publish.mjs.map +0 -7
  165. package/dist/modules/compile.d.mts +0 -3
  166. package/dist/modules/compile.mjs +0 -58
  167. package/dist/modules/compile.mjs.map +0 -7
  168. package/dist/modules/index.browser.d.mts +0 -4
  169. package/dist/modules/index.browser.mjs +0 -8
  170. package/dist/modules/index.browser.mjs.map +0 -7
  171. package/examples/custom-harness/README.md +0 -16
  172. package/examples/custom-harness/agent.ts +0 -154
  173. package/examples/custom-sandbox/README.md +0 -12
  174. package/examples/custom-sandbox/agent.ts +0 -14
  175. package/examples/custom-sandbox/sandbox.ts +0 -24
  176. package/examples/release-scout/agent/agent.ts +0 -22
  177. package/examples/release-scout/agent/channels/github-signature.ts +0 -27
  178. package/examples/release-scout/agent/channels/github.ts +0 -32
  179. package/examples/release-scout/agent/connections/linear.ts +0 -9
  180. package/examples/release-scout/agent/hooks/audit.ts +0 -24
  181. package/examples/release-scout/agent/instructions/org-context.ts +0 -26
  182. package/examples/release-scout/agent/instructions.md +0 -2
  183. package/examples/release-scout/agent/sandbox.ts +0 -20
  184. package/examples/release-scout/agent/schedules/daily-digest.md +0 -7
  185. package/examples/release-scout/agent/skills/triage/SKILL.md +0 -8
  186. package/examples/release-scout/agent/skills/triage/checklist.md +0 -3
  187. package/examples/release-scout/agent/tools/lookup_release_notes.ts +0 -24
  188. package/examples/release-scout/client.ts +0 -122
package/README.md CHANGED
@@ -1,43 +1,228 @@
1
1
  # @finalai/agents
2
2
 
3
- SDK for defining, publishing, and using agents. Authoring helpers are implemented in
4
- `@finalai/agent-definition`; Final-specific bindings come from
5
- `@finalai/final-agent-provider`.
3
+ SDK for defining agents and starting them. An agent is a value that lists every
4
+ part explicitly and states what it requires; whoever starts it provides the
5
+ rest. Nothing is built or deployed: the agent's document travels with the call
6
+ that starts it.
6
7
 
7
8
  ```ts
8
- import { defineAgent } from '@finalai/agents';
9
- import { serverlessPi } from '@finalai/agents/harnesses';
9
+ // agent.ts
10
+ import { defineAgent, defineInProcessTool, defineServerlessTool, markdown } from '@finalai/agents';
11
+ import { FinalHarness } from '@finalai/agents/harnesses';
12
+ import * as z from 'zod';
13
+ import { orders } from './db.js';
10
14
 
11
- export default defineAgent({
12
- name: 'Assistant',
13
- harness: serverlessPi({
14
- credentials: { payer: 'agent-owner', tryInOrder: [{ kind: 'platform' }] },
15
- }),
15
+ // Self-contained, so it runs on Final's runtime even when this app is not running.
16
+ const lookupReleaseNotes = defineServerlessTool({
17
+ description: 'Fetch the published notes for a release.',
18
+ inputSchema: z.object({ version: z.string() }),
19
+ execute: async ({ version }) => {
20
+ const response = await fetch(`https://releases.example.com/${version}.md`);
21
+ return { found: response.ok, notes: response.ok ? await response.text() : null };
22
+ },
23
+ });
24
+
25
+ // Uses this app's database, so it runs in the process that created the session.
26
+ const findOrder = defineInProcessTool({
27
+ description: 'Look up an order by id.',
28
+ inputSchema: z.object({ id: z.string() }),
29
+ execute: async ({ id }) => orders.find(id),
30
+ });
31
+
32
+ export const agent = defineAgent({
33
+ name: 'Release Scout',
34
+ instructions: markdown('./instructions.md', { from: import.meta.url }),
35
+ tools: { lookup_release_notes: lookupReleaseNotes, find_order: findOrder },
36
+ require: {
37
+ harness: {
38
+ permissionMode: 'ask', // a limit: binding
39
+ recommended: { harness: FinalHarness.Pi, model: 'gpt-6.1-sol' }, // a hint
40
+ },
41
+ compute: { files: 'write', shell: 'execute' }, // keyed by capability
42
+ integrations: {
43
+ issues: { description: 'Issue tracker', tools: { deny: ['delete_*'] } },
44
+ },
45
+ },
16
46
  });
17
47
  ```
18
48
 
19
- Use `@finalai/agents/client` for definitions, sessions, conversations, approvals,
20
- attachments, schedules, sandbox access, and realtime. Use `final-agents --help`
21
- for CLI commands. Compilation requires Node 26 and ships its assets through
22
- `agent-definition`.
49
+ ```ts
50
+ // run.ts
51
+ import { createClient } from '@finalai/agents/client';
52
+ import { finalCredits, serverlessPi } from '@finalai/agents/harnesses';
53
+ import { oauth } from '@finalai/agents/integrations';
54
+ import { agent } from './agent.js';
55
+
56
+ const client = createClient({ auth: { apiKey: process.env.FINAL_API_KEY } });
57
+ const project = client.project({ id: 'prj_01JENGINEERING' });
58
+
59
+ const linear = await project.integrations.create({
60
+ name: 'linear',
61
+ mcp: { url: 'https://mcp.linear.app/mcp' },
62
+ auth: oauth({ credential: 'shared' }),
63
+ });
64
+
65
+ // Pi runs as a worker program, in a Workers sandbox the session owns (created for you).
66
+ const { response } = await project.sessions.create({
67
+ agent,
68
+ provide: {
69
+ harness: serverlessPi({
70
+ model: 'gpt-6.1-sol',
71
+ inference: finalCredits(),
72
+ }),
73
+ integrations: { issues: linear },
74
+ },
75
+ message: 'Did 2.4.1 ship?',
76
+ });
77
+ console.log(await response?.text());
78
+ ```
23
79
 
24
- Credential-chain declarations select which credentials an agent may use and in
25
- which order. Set the payer policy explicitly in the harness configuration.
80
+ ## Requirements and `provide`
26
81
 
27
- For custom provider implementations, import contracts from `@finalai/agent-provider`,
28
- sandbox adapters from `@finalai/agent-provider/sandbox`, and conformance tools from
29
- `@finalai/agent-provider/conformance`. Run a harness check with
30
- `final-agents conformance ./harness.ts`.
82
+ | The agent declares | The caller provides | If not provided |
83
+ | ------------------------------------------------------- | ------------------------ | --------------------------------------------------------------------------------------------------- |
84
+ | `require.harness`: a permission ceiling, a hint | harness settings, inline | the call fails; a harness is never optional |
85
+ | `require.compute.<capability>`: the access it needs | a sandbox per capability | `files` and `shell` run in the calling process; `computerUse` and `browserUse` fail unless optional |
86
+ | `require.integrations.<slot>`: a description, a ceiling | an integration per slot | the call fails, unless the slot is `optional: true` and its tools are simply absent |
31
87
 
32
- Use `FINAL_API_HOST` with `FINAL_API_KEY` to select a deployment once for build and
33
- publish; an explicit `--host` overrides it. Use `defineHostedConnection` for a named
34
- connection resolved by hosting at session start. `defineFinalConnection()` uses
35
- the same path with the `final` binding. Explicit URL declarations remain static.
36
- See the repository's [hosting guide](HOSTING.md) for provider contexts,
37
- resource lookup, and the required hosting integration.
88
+ `provide` is a plain object on every call that starts work:
89
+ `project.sessions.create`, `project.conversations.create` (per participant),
90
+ `conversations.direct` and `.home`, `handle.addParticipant`,
91
+ `handle.participants.provide(participantId, patch)` and
92
+ `project.channels.install({ agents: { provide } })`. Sandbox and integration
93
+ handles are sent as their ids. Before sending, the SDK runs the same
94
+ requirements check the platform runs; anything missing throws a
95
+ `requirements_unmet` error with the list (`isRequirementsUnmetError(cause)`,
96
+ `cause.requirements`), and nothing is created.
38
97
 
39
- Local previews can use explicitly declared secrets from `AGENT_LOCAL_SECRETS_JSON`. Installed app operations and member and chat capabilities require an authenticated host. Embedders may supply the same opaque credential facade to `startDevServer`; raw application credentials are never exposed to authored modules.
98
+ `sessions.create` and `conversations.create` take an `id` you choose, so a
99
+ sandbox created first can be owned by the session or conversation it is for
100
+ (`project.sandboxes.create(environment, { setup, ownedBy, idempotencyKey })`).
101
+ `conversations.findHome()` and `findDirect({ agent })` look up without creating.
102
+
103
+ ## Where things run
104
+
105
+ - **The model's files and shell** run on whatever sandbox is provided
106
+ (`computer(...)` and `device(...)` from `@finalai/agents/sandboxes`, or any
107
+ provider). Left out, they run in the process that created the session, on its
108
+ machine, over a connection the client opens to the platform.
109
+ - **An in-process tool or hook** runs in the process that created the session
110
+ and can use anything that process holds. When that process exits the session
111
+ carries on and the tool reports itself unavailable.
112
+ - **A serverless tool or hook** is self-contained: its source is part of the
113
+ agent's data and it runs on Final's runtime. It cannot import packages or use
114
+ outside variables; bundle a library into one module and pass it as `source`.
115
+
116
+ The compute default is not safe for a server: a backend that leaves out `shell`
117
+ gives the model a shell in that backend. A server provides every capability and
118
+ creates its client with `createClient({ auth, localCompute: false })`, so an
119
+ omission fails instead.
120
+
121
+ An agent is always passed as an object: the value you defined, or one fetched
122
+ with `project.agents.get({ name } | { id } | { hash })`. A fetched agent is data
123
+ only; starting one that has in-process tools fails and names them.
124
+
125
+ ## Harnesses, inference and integrations
126
+
127
+ `@finalai/agents/harnesses` builds harness settings for Final's harnesses
128
+ (`serverlessPi`, `serverlessFinal`, `serverlessNanocodeClaude`,
129
+ `serverlessNanocodeCodex` as worker programs; `claudeCode` and `codex` as a
130
+ process on a machine, or `environment: atUrl({ url, hop })` for one already
131
+ running) and the inference sources a harness pays with, first available wins:
132
+
133
+ ```ts
134
+ serverlessNanocodeClaude({
135
+ model: 'claude-opus-5-5',
136
+ inference: [subscription(), apiKey('ANTHROPIC_API_KEY'), finalCredits()],
137
+ });
138
+ ```
139
+
140
+ `project.harnesses.check({ agent, harness })` says whether settings suit an
141
+ agent and where the harness would run.
142
+
143
+ A harness is data you can define and publish yourself, with the ACP adapter it
144
+ runs behind when it does not speak ACP v2:
145
+
146
+ ```ts
147
+ import {
148
+ CredentialDelivery,
149
+ defineHarness,
150
+ InferenceSourceKind,
151
+ PermissionLevel,
152
+ } from '@finalai/agents';
153
+
154
+ export const harness = defineHarness({
155
+ configurationSchema: { type: 'object', properties: { model: { type: 'string' } } },
156
+ features: [],
157
+ lowestPermission: PermissionLevel.Ask,
158
+ inference: { kinds: [InferenceSourceKind.ApiKey], delivery: CredentialDelivery.AtOpen },
159
+ native: { files: {}, shell: {} },
160
+ interface: 'my-cli-rpc',
161
+ adapter: 'my-cli-acp',
162
+ run: {
163
+ process: {
164
+ command: 'my-cli',
165
+ args: [
166
+ '--rpc',
167
+ { when: 'configuration.model', args: ['--model', '{{configuration.model}}'] },
168
+ ],
169
+ },
170
+ },
171
+ });
172
+ ```
173
+
174
+ `project.harnesses.publish({ harness, name })` and
175
+ `project.acpAdapters.publish({ adapter, name })` give them names harness
176
+ settings use (`{ harness: 'my-cli', environment: box }`).
177
+ `project.harnesses.allowances` lists, allows and revokes the harnesses
178
+ subscriptions may reach. A harness reached some other way (a hosted fleet)
179
+ carries its own code: `defineHarness({ …, provider: defineHarnessProvider({ open,
180
+ resume, park, close, health }) })`, self-contained like a serverless tool. `@finalai/agents/integrations` has the auth builders (`oauth`, `secret`,
181
+ `platformIdentity`) and `finalGateway({ url })`. A person's own sign-in is never a
182
+ requirement: the platform asks them on first use.
183
+
184
+ ## Publishing
185
+
186
+ ```sh
187
+ final-agents print ./agent.ts # the document as JSON; calls nothing
188
+ final-agents publish ./agent.ts --name release-scout # FINAL_API_KEY, FINAL_PROJECT_ID
189
+ final-agents publish ./harness.ts --name my-cli # a harness or ACP adapter export
190
+ ```
191
+
192
+ `publish` is `project.agents.publish({ agent, name })`: it stores the document
193
+ by its content hash and points the name at it. `project.agents.parse(json)`
194
+ reads a printed document back as an agent. `final-agents conformance ./harness.ts`
195
+ runs the harness conformance kit.
196
+
197
+ A project that claims a publisher handle (`project.publisher.claim({ handle })`)
198
+ can make names public: `publish({ …, visibility: 'public' })`, or
199
+ `project.publicNames.publish({ kind, name })`. Any organization then names them
200
+ as `handle/name`, and `client.publishers.get(handle)` lists them.
201
+
202
+ ## Events and webhooks
203
+
204
+ `project.events.list({ after })` reads what changed in a project and those
205
+ below it, in commit order; `project.events.stream()` keeps polling.
206
+ `project.eventSubscriptions.create({ url, kinds })` pushes the same events to
207
+ your endpoint, signed per Standard Webhooks:
208
+
209
+ ```ts
210
+ import { verifyWebhook } from '@finalai/agents/webhooks';
211
+
212
+ const result = await verifyWebhook({
213
+ payload: await request.text(),
214
+ headers: request.headers,
215
+ secret,
216
+ });
217
+ if (!result.ok) return new Response(null, { status: 400 });
218
+ for (const event of result.delivery.events) {
219
+ // Payloads are ids and state; read details through the API.
220
+ }
221
+ ```
40
222
 
41
- Authored channel applications use `defineChannel` from `/channels` and compile into the published bundle. Use `bundleRef('channels/support')` in `agent.ts` to configure an existing channel module; its credentials and routes are derived from that module. Credential enums and opaque credential types are available from the same facade.
223
+ `@finalai/agents/verify` verifies the tokens the platform signs: the
224
+ platform-identity assertions your integrations and providers receive, and access tokens.
42
225
 
43
- `client.definitions.publish({ definition, ref, activate: false })` publishes an approved immutable source revision without changing the live agent, routes, listeners, or schedules. The CLI equivalent is `publish --no-activate`. Credential declarations still need normal administrator approval. Install an exported channel with `channel install <key> --revision <id> --project <id> --install <id>`; use `--replace` or `channelBindings.create({ ..., replace: true })` to explicitly update an active binding while retaining its ID and binding base URL. Omitted configuration preserves current settings during replacement; an explicit empty configuration resets to source defaults. New source publication never silently updates an installed revision pin.
226
+ See [examples/release-scout](examples/release-scout) and the repository's
227
+ [hosting guide](HOSTING.md) for what a platform implementing the API
228
+ provides, including the local host connection.
@@ -0,0 +1,24 @@
1
+ import { type AgentDocumentIface } from '@finalai/agent-provider/document';
2
+ import type { InProcessCodeRegistryIface } from '@finalai/agent-provider/code-host';
3
+ import { type AgentInfoIface, type AgentRefInputIface } from '@finalai/agent-protocol/agent-platform';
4
+ /** What `defineAgent` returns; read through `AgentValueCodecIface`. */
5
+ export type AgentValue = object;
6
+ /** An agent as `sessions.create` and participants take it. */
7
+ export type AgentInput = AgentInfoIface | AgentValue;
8
+ /** How the SDK reads an agent value; a seam over `@finalai/agent-definition`. */
9
+ export interface AgentValueCodecIface {
10
+ documentOf: (agent: AgentValue) => AgentDocumentIface | Promise<AgentDocumentIface>;
11
+ /** The bodies of its in-process tools, hooks and approval predicates. */
12
+ inProcessCodeOf: (agent: AgentValue) => InProcessCodeRegistryIface | Promise<InProcessCodeRegistryIface>;
13
+ }
14
+ export interface ResolvedAgentIface {
15
+ hash: string;
16
+ document: AgentDocumentIface;
17
+ /** The ref sent on the wire; the document travels with a value. */
18
+ ref: AgentRefInputIface;
19
+ /** Names of its tools and hooks whose code only runs in the creating process. */
20
+ inProcess: string[];
21
+ /** Null when this process does not hold the agent's code (a fetched agent). */
22
+ code: InProcessCodeRegistryIface | null;
23
+ }
24
+ export declare const resolveAgentInput: (agent: unknown, codec: AgentValueCodecIface) => Promise<ResolvedAgentIface>;
@@ -0,0 +1,46 @@
1
+ import {
2
+ agentDocumentHash,
3
+ agentDocumentSchema,
4
+ inProcessCodeOf
5
+ } from "@finalai/agent-provider/document";
6
+ import { jsonObjectSchema } from "@finalai/agent-protocol";
7
+ import {
8
+ agentInfoSchema
9
+ } from "@finalai/agent-protocol/agent-platform";
10
+ import { clientError, ClientErrorCode } from "./errors.mjs";
11
+ const invalidAgent = (message) => clientError({ message, status: 0, code: ClientErrorCode.InvalidRequest });
12
+ const resolveAgentInput = async (agent, codec) => {
13
+ if (typeof agent === "string")
14
+ throw invalidAgent(
15
+ `An agent is passed as an object, not the string "${agent}": pass the value you defined, or fetch it with project.agents.get({ name })`
16
+ );
17
+ if (agent == null || typeof agent !== "object")
18
+ throw invalidAgent("An agent is passed as the value you defined or one you fetched");
19
+ const fetched = agentInfoSchema.safeParse(agent);
20
+ if (fetched.success) {
21
+ const document2 = agentDocumentSchema.safeParse(fetched.data.document);
22
+ if (!document2.success)
23
+ throw invalidAgent(`The fetched agent's document is not valid: ${document2.error.message}`);
24
+ return {
25
+ hash: fetched.data.hash,
26
+ document: document2.data,
27
+ // A published agent is stored; one parsed from a printed document may not be.
28
+ ref: fetched.data.id == null ? { hash: fetched.data.hash, document: fetched.data.document } : { hash: fetched.data.hash },
29
+ inProcess: inProcessCodeOf(document2.data),
30
+ code: null
31
+ };
32
+ }
33
+ const document = await codec.documentOf(agent);
34
+ const hash = await agentDocumentHash(document);
35
+ return {
36
+ hash,
37
+ document,
38
+ ref: { hash, document: jsonObjectSchema.parse(JSON.parse(JSON.stringify(document))) },
39
+ inProcess: inProcessCodeOf(document),
40
+ code: await codec.inProcessCodeOf(agent)
41
+ };
42
+ };
43
+ export {
44
+ resolveAgentInput
45
+ };
46
+ //# sourceMappingURL=agent-input.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/agent-client/agent-input.ts"],
4
+ "sourcesContent": ["import {\n agentDocumentHash,\n agentDocumentSchema,\n inProcessCodeOf,\n type AgentDocumentIface,\n} from '@finalai/agent-provider/document';\nimport type { InProcessCodeRegistryIface } from '@finalai/agent-provider/code-host';\nimport { jsonObjectSchema } from '@finalai/agent-protocol';\nimport {\n agentInfoSchema,\n type AgentInfoIface,\n type AgentRefInputIface,\n} from '@finalai/agent-protocol/agent-platform';\nimport { clientError, ClientErrorCode } from \"./errors.mjs\";\n\n// An agent is always passed as an object: a value the caller defined\n// (`defineAgent`), whose in-process code this process holds, or one fetched\n// with `project.agents.get`, which is data only.\n\n/** What `defineAgent` returns; read through `AgentValueCodecIface`. */\nexport type AgentValue = object;\n\n/** An agent as `sessions.create` and participants take it. */\nexport type AgentInput = AgentInfoIface | AgentValue;\n\n/** How the SDK reads an agent value; a seam over `@finalai/agent-definition`. */\nexport interface AgentValueCodecIface {\n documentOf: (agent: AgentValue) => AgentDocumentIface | Promise<AgentDocumentIface>;\n /** The bodies of its in-process tools, hooks and approval predicates. */\n inProcessCodeOf: (\n agent: AgentValue,\n ) => InProcessCodeRegistryIface | Promise<InProcessCodeRegistryIface>;\n}\n\nexport interface ResolvedAgentIface {\n hash: string;\n document: AgentDocumentIface;\n /** The ref sent on the wire; the document travels with a value. */\n ref: AgentRefInputIface;\n /** Names of its tools and hooks whose code only runs in the creating process. */\n inProcess: string[];\n /** Null when this process does not hold the agent's code (a fetched agent). */\n code: InProcessCodeRegistryIface | null;\n}\n\nconst invalidAgent = (message: string) =>\n clientError({ message, status: 0, code: ClientErrorCode.InvalidRequest });\n\nexport const resolveAgentInput = async (\n agent: unknown,\n codec: AgentValueCodecIface,\n): Promise<ResolvedAgentIface> => {\n if (typeof agent === 'string')\n throw invalidAgent(\n `An agent is passed as an object, not the string \"${agent}\": pass the value you defined, or fetch it with project.agents.get({ name })`,\n );\n if (agent == null || typeof agent !== 'object')\n throw invalidAgent('An agent is passed as the value you defined or one you fetched');\n const fetched = agentInfoSchema.safeParse(agent);\n if (fetched.success) {\n const document = agentDocumentSchema.safeParse(fetched.data.document);\n if (!document.success)\n throw invalidAgent(`The fetched agent's document is not valid: ${document.error.message}`);\n return {\n hash: fetched.data.hash,\n document: document.data,\n // A published agent is stored; one parsed from a printed document may not be.\n ref:\n fetched.data.id == null\n ? { hash: fetched.data.hash, document: fetched.data.document }\n : { hash: fetched.data.hash },\n inProcess: inProcessCodeOf(document.data),\n code: null,\n };\n }\n const document = await codec.documentOf(agent);\n const hash = await agentDocumentHash(document);\n return {\n hash,\n document,\n ref: { hash, document: jsonObjectSchema.parse(JSON.parse(JSON.stringify(document))) },\n inProcess: inProcessCodeOf(document),\n code: await codec.inProcessCodeOf(agent),\n };\n};\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,OAGK;AACP,SAAS,aAAa,uBAAuB;AAgC7C,MAAM,eAAe,CAAC,YACpB,YAAY,EAAE,SAAS,QAAQ,GAAG,MAAM,gBAAgB,eAAe,CAAC;AAEnE,MAAM,oBAAoB,OAC/B,OACA,UACgC;AAChC,MAAI,OAAO,UAAU;AACnB,UAAM;AAAA,MACJ,oDAAoD,KAAK;AAAA,IAC3D;AACF,MAAI,SAAS,QAAQ,OAAO,UAAU;AACpC,UAAM,aAAa,gEAAgE;AACrF,QAAM,UAAU,gBAAgB,UAAU,KAAK;AAC/C,MAAI,QAAQ,SAAS;AACnB,UAAMA,YAAW,oBAAoB,UAAU,QAAQ,KAAK,QAAQ;AACpE,QAAI,CAACA,UAAS;AACZ,YAAM,aAAa,8CAA8CA,UAAS,MAAM,OAAO,EAAE;AAC3F,WAAO;AAAA,MACL,MAAM,QAAQ,KAAK;AAAA,MACnB,UAAUA,UAAS;AAAA;AAAA,MAEnB,KACE,QAAQ,KAAK,MAAM,OACf,EAAE,MAAM,QAAQ,KAAK,MAAM,UAAU,QAAQ,KAAK,SAAS,IAC3D,EAAE,MAAM,QAAQ,KAAK,KAAK;AAAA,MAChC,WAAW,gBAAgBA,UAAS,IAAI;AAAA,MACxC,MAAM;AAAA,IACR;AAAA,EACF;AACA,QAAM,WAAW,MAAM,MAAM,WAAW,KAAK;AAC7C,QAAM,OAAO,MAAM,kBAAkB,QAAQ;AAC7C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,KAAK,EAAE,MAAM,UAAU,iBAAiB,MAAM,KAAK,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC,EAAE;AAAA,IACpF,WAAW,gBAAgB,QAAQ;AAAA,IACnC,MAAM,MAAM,MAAM,gBAAgB,KAAK;AAAA,EACzC;AACF;",
6
+ "names": ["document"]
7
+ }
@@ -1,23 +1,135 @@
1
- import { type ChannelRouteIface, type ChannelSeenPlaceIface, type ConnectChannelPlaceRequestIface, type CreateChannelBindingRequestIface, type CreateChannelBindingResponseIface } from '@finalai/agent-protocol/agent-platform';
2
- import { type ClientContextIface, type SignalOptionsIface } from "./context.mjs";
1
+ import { type ActorInputIface, type ChannelAppIface, type ChannelBindingIface, type ChannelIdentityLinkIface, type ChannelIdentityLinkProgressIface, type ChannelIface, type ChannelSeenPlaceIface, type ChannelTenantTicketIface, type ChannelTicketIface, type CompleteChannelIdentityLinkRequestIface, type CompleteChannelPlaceConnectionRequestIface, type CreateChannelAppRequestIface, type DefinitionVisibility, type InstallChannelRequestIface, type InstalledChannelIface, type PublishChannelResponseIface, type UpdateChannelAppRequestIface, type UpdateChannelBindingRequestIface } from '@finalai/agent-protocol/agent-platform';
2
+ import { type ClientContextIface, type EnumInput, type SignalOptionsIface } from "./context.mjs";
3
+ import { type ProvideIface } from "./provide.mjs";
4
+ /** A channel value's source, as `channels.publish({ channel })` sends it. */
5
+ export interface ChannelSourceIface {
6
+ source: string;
7
+ export?: string;
8
+ }
9
+ /** How the SDK turns a channel value into its source; a seam over `@finalai/agent-definition`. */
10
+ export type ChannelSourceOf = (channel: object) => ChannelSourceIface;
11
+ export type PublishChannelArgsIface = {
12
+ name: string;
13
+ /** `public` also makes the name public under the project's publisher handle. */
14
+ visibility?: EnumInput<DefinitionVisibility>;
15
+ /** A channel app of this project that installs of the publication use unless they bring their own. */
16
+ app?: string;
17
+ } & SignalOptionsIface & ({
18
+ channel: object;
19
+ } | {
20
+ source: string;
21
+ export?: string;
22
+ });
23
+ export type InstallChannelArgsIface = Omit<InstallChannelRequestIface, 'agents'> & {
24
+ /** What the agent gets in every chat this install creates. */
25
+ agents: {
26
+ provide: ProvideIface;
27
+ };
28
+ } & SignalOptionsIface;
29
+ export type UpdateChannelBindingArgsIface = Omit<UpdateChannelBindingRequestIface, 'agents'> & {
30
+ bindingId: string;
31
+ agents?: {
32
+ provide: ProvideIface;
33
+ };
34
+ } & SignalOptionsIface;
35
+ export interface ProjectChannelsApiIface {
36
+ publish: (args: PublishChannelArgsIface) => Promise<PublishChannelResponseIface>;
37
+ get: (selector: ({
38
+ name: string;
39
+ } | {
40
+ hash: string;
41
+ }) & SignalOptionsIface) => Promise<ChannelIface>;
42
+ /**
43
+ * Installs a channel in the project. Fails with `requirements_unmet`, and
44
+ * installs nothing, unless `agents.provide` meets the agent's requirements
45
+ * and the channel's app requirement is met.
46
+ */
47
+ install: (args: InstallChannelArgsIface) => Promise<InstalledChannelIface>;
48
+ /** The project's installs, newest first. */
49
+ installs: (options?: SignalOptionsIface & {
50
+ includeArchived?: boolean;
51
+ }) => Promise<ChannelBindingIface[]>;
52
+ }
3
53
  export interface ChannelBindingsApiIface {
4
- create(args: CreateChannelBindingRequestIface & SignalOptionsIface): Promise<CreateChannelBindingResponseIface>;
5
- places(args: {
54
+ /** One install, with whether its agent's requirements are met now. */
55
+ get: (args: {
6
56
  bindingId: string;
7
- } & SignalOptionsIface): Promise<ChannelSeenPlaceIface[]>;
8
- routes(args: {
9
- conversationId: string;
10
- } & SignalOptionsIface): Promise<ChannelRouteIface[]>;
11
- connect(args: ConnectChannelPlaceRequestIface & {
12
- conversationId: string;
13
- } & SignalOptionsIface): Promise<{
14
- id: string;
57
+ } & SignalOptionsIface) => Promise<ChannelBindingIface>;
58
+ /** Fails with `revision_conflict` unless `revision` is the one last read, and with `requirements_unmet` when the change would leave them unmet. */
59
+ update: (args: UpdateChannelBindingArgsIface) => Promise<InstalledChannelIface>;
60
+ /** Ends the install: its connected places, tenants, listeners and the links made through it. */
61
+ uninstall: (args: {
62
+ bindingId: string;
63
+ } & SignalOptionsIface) => Promise<{
64
+ archivedAt: string | null;
15
65
  }>;
16
- disconnect(args: {
17
- conversationId: string;
66
+ /** A single-use link that installs the provider app for one tenant (a workspace, a server). */
67
+ tenantTicket: (args: {
68
+ bindingId: string;
69
+ } & SignalOptionsIface) => Promise<ChannelTenantTicketIface>;
70
+ /** The provider places the install has seen. */
71
+ places: (args: {
72
+ bindingId: string;
73
+ } & SignalOptionsIface) => Promise<ChannelSeenPlaceIface[]>;
74
+ }
75
+ export interface ChannelAppsApiIface {
76
+ /** Registers the provider application's credentials; secret values stay project secrets. */
77
+ create: (args: CreateChannelAppRequestIface & SignalOptionsIface) => Promise<ChannelAppIface>;
78
+ /** The apps of the project and its ancestors. */
79
+ list: (options?: SignalOptionsIface) => Promise<ChannelAppIface[]>;
80
+ update: (args: UpdateChannelAppRequestIface & {
81
+ id: string;
82
+ } & SignalOptionsIface) => Promise<ChannelAppIface>;
83
+ /** Refused while a live install or publication uses the app. */
84
+ delete: (args: {
85
+ id: string;
86
+ } & SignalOptionsIface) => Promise<void>;
87
+ }
88
+ /** The actor an API key or app acts for, by its external id. */
89
+ export interface ActorOptionIface {
90
+ actor?: string;
91
+ }
92
+ export interface ChannelTicketsApiIface {
93
+ /** What a ticket from an installer's link or connect page is for. */
94
+ get: (args: {
95
+ ticket: string;
96
+ } & ActorOptionIface & SignalOptionsIface) => Promise<ChannelTicketIface>;
97
+ /** Links the ticket's channel account to the caller's person, or to `actor`. */
98
+ link: (args: {
99
+ ticket: string;
100
+ } & CompleteChannelIdentityLinkRequestIface & SignalOptionsIface) => Promise<ChannelIdentityLinkProgressIface>;
101
+ /** Connects the ticket's place to a conversation the caller manages. */
102
+ connect: (args: {
103
+ ticket: string;
104
+ } & CompleteChannelPlaceConnectionRequestIface & SignalOptionsIface) => Promise<{
18
105
  routeId: string;
19
- } & SignalOptionsIface): Promise<{
20
- ok: boolean;
21
106
  }>;
22
107
  }
108
+ export interface IdentityLinksApiIface {
109
+ /** The channel accounts linked to the caller's person, or to `actor`. */
110
+ list: (options?: ActorOptionIface & SignalOptionsIface) => Promise<ChannelIdentityLinkIface[]>;
111
+ /** Chooses where the person's direct messages to the channel land. */
112
+ update: (args: {
113
+ id: string;
114
+ directConversationId: string | null;
115
+ actor?: ActorInputIface;
116
+ } & SignalOptionsIface) => Promise<void>;
117
+ /** Unlinks the account. */
118
+ delete: (args: {
119
+ id: string;
120
+ } & ActorOptionIface & SignalOptionsIface) => Promise<void>;
121
+ }
122
+ export declare const createProjectChannelsApi: (args: {
123
+ context: ClientContextIface;
124
+ projectId: string;
125
+ sourceOf: ChannelSourceOf;
126
+ }) => ProjectChannelsApiIface;
23
127
  export declare const createChannelBindingsApi: (ctx: ClientContextIface) => ChannelBindingsApiIface;
128
+ export declare const createChannelAppsApi: (args: {
129
+ context: ClientContextIface;
130
+ projectId: string;
131
+ }) => ChannelAppsApiIface;
132
+ export declare const createChannelTicketsApi: (ctx: ClientContextIface) => ChannelTicketsApiIface;
133
+ export declare const createIdentityLinksApi: (ctx: ClientContextIface) => IdentityLinksApiIface;
134
+ /** The default `ChannelSourceOf` when no codec is available. */
135
+ export declare const noChannelSource: ChannelSourceOf;