@finalai/agents 0.10.0 → 0.12.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 (185) 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 +52 -3
  7. package/dist/modules/agent-client/channels.mjs +71 -10
  8. package/dist/modules/agent-client/channels.mjs.map +2 -2
  9. package/dist/modules/agent-client/client.d.mts +85 -20
  10. package/dist/modules/agent-client/client.mjs +74 -21
  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 +85 -0
  15. package/dist/modules/agent-client/conversation-resources.mjs +150 -0
  16. package/dist/modules/agent-client/conversation-resources.mjs.map +7 -0
  17. package/dist/modules/agent-client/conversations.d.mts +116 -38
  18. package/dist/modules/agent-client/conversations.mjs +379 -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 +43 -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 +65 -0
  75. package/dist/modules/agent-client/sandboxes.mjs +130 -0
  76. package/dist/modules/agent-client/sandboxes.mjs.map +7 -0
  77. package/dist/modules/agent-client/schedules.d.mts +24 -0
  78. package/dist/modules/agent-client/schedules.mjs +56 -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 +42 -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/index.d.mts +0 -1
  133. package/dist/modules/authoring/index.mjs +0 -2
  134. package/dist/modules/authoring/index.mjs.map +0 -7
  135. package/dist/modules/authoring/instructions.d.mts +0 -1
  136. package/dist/modules/authoring/instructions.mjs +0 -2
  137. package/dist/modules/authoring/instructions.mjs.map +0 -7
  138. package/dist/modules/authoring/providers.d.mts +0 -2
  139. package/dist/modules/authoring/providers.mjs +0 -1
  140. package/dist/modules/authoring/providers.mjs.map +0 -7
  141. package/dist/modules/cli/build.d.mts +0 -22
  142. package/dist/modules/cli/build.mjs +0 -77
  143. package/dist/modules/cli/build.mjs.map +0 -7
  144. package/dist/modules/cli/channel-install.d.mts +0 -12
  145. package/dist/modules/cli/channel-install.mjs +0 -25
  146. package/dist/modules/cli/channel-install.mjs.map +0 -7
  147. package/dist/modules/cli/channel-socket.d.mts +0 -9
  148. package/dist/modules/cli/channel-socket.mjs +0 -114
  149. package/dist/modules/cli/channel-socket.mjs.map +0 -7
  150. package/dist/modules/cli/dev.d.mts +0 -26
  151. package/dist/modules/cli/dev.mjs +0 -311
  152. package/dist/modules/cli/dev.mjs.map +0 -7
  153. package/dist/modules/cli/files.d.mts +0 -18
  154. package/dist/modules/cli/files.mjs +0 -66
  155. package/dist/modules/cli/files.mjs.map +0 -7
  156. package/dist/modules/cli/harness-descriptions.d.mts +0 -20
  157. package/dist/modules/cli/harness-descriptions.mjs +0 -70
  158. package/dist/modules/cli/harness-descriptions.mjs.map +0 -7
  159. package/dist/modules/cli/publish.d.mts +0 -15
  160. package/dist/modules/cli/publish.mjs +0 -92
  161. package/dist/modules/cli/publish.mjs.map +0 -7
  162. package/dist/modules/compile.d.mts +0 -3
  163. package/dist/modules/compile.mjs +0 -58
  164. package/dist/modules/compile.mjs.map +0 -7
  165. package/dist/modules/index.browser.d.mts +0 -4
  166. package/dist/modules/index.browser.mjs +0 -8
  167. package/dist/modules/index.browser.mjs.map +0 -7
  168. package/examples/custom-harness/README.md +0 -16
  169. package/examples/custom-harness/agent.ts +0 -154
  170. package/examples/custom-sandbox/README.md +0 -12
  171. package/examples/custom-sandbox/agent.ts +0 -14
  172. package/examples/custom-sandbox/sandbox.ts +0 -24
  173. package/examples/release-scout/agent/agent.ts +0 -22
  174. package/examples/release-scout/agent/channels/github-signature.ts +0 -27
  175. package/examples/release-scout/agent/channels/github.ts +0 -32
  176. package/examples/release-scout/agent/connections/linear.ts +0 -9
  177. package/examples/release-scout/agent/hooks/audit.ts +0 -24
  178. package/examples/release-scout/agent/instructions/org-context.ts +0 -26
  179. package/examples/release-scout/agent/instructions.md +0 -2
  180. package/examples/release-scout/agent/sandbox.ts +0 -20
  181. package/examples/release-scout/agent/schedules/daily-digest.md +0 -7
  182. package/examples/release-scout/agent/skills/triage/SKILL.md +0 -8
  183. package/examples/release-scout/agent/skills/triage/checklist.md +0 -3
  184. package/examples/release-scout/agent/tools/lookup_release_notes.ts +0 -24
  185. package/examples/release-scout/client.ts +0 -122
@@ -1,92 +0,0 @@
1
- import { isClientError } from "../agent-client/errors.mjs";
2
- import { DefinitionRepositoryKind } from "../agent-client/index.mjs";
3
- import { compileAndPrint } from "./build.mjs";
4
- import { fileChanges, readLocalFiles } from "./files.mjs";
5
- import { errorLines, publishResultLines } from "./output.mjs";
6
- const remoteFiles = async (args) => {
7
- try {
8
- const listing = await args.client.definitions.files({
9
- definition: args.definition.id,
10
- ref: args.branch
11
- });
12
- return {
13
- commitSha: listing.commitSha,
14
- files: Object.fromEntries(listing.files.map((file) => [file.path, file.content]))
15
- };
16
- } catch (cause) {
17
- if (isClientError(cause) && cause.status === 404) return { commitSha: null, files: {} };
18
- throw cause;
19
- }
20
- };
21
- const commitCheckout = async (args) => {
22
- const { client, output, message } = args.publish;
23
- const remote = await remoteFiles({ client, definition: args.definition, branch: args.branch });
24
- const changes = fileChanges({ local: args.local, remote: remote.files });
25
- if (changes.length === 0 && remote.commitSha != null) {
26
- output.stdout(`no changes; publishing ${args.branch} at ${remote.commitSha}`);
27
- return remote.commitSha;
28
- }
29
- const request = {
30
- definition: args.definition.id,
31
- files: changes,
32
- message,
33
- branch: args.branch
34
- };
35
- if (remote.commitSha != null) request.parentSha = remote.commitSha;
36
- const committed = await client.definitions.commit(request);
37
- const deleted = changes.filter((change) => change.content == null).length;
38
- output.stdout(
39
- `committed ${committed.commitSha} to ${committed.branch} (${changes.length - deleted} written, ${deleted} deleted)`
40
- );
41
- return committed.commitSha;
42
- };
43
- const runPublish = async (args) => {
44
- const { client, output } = args;
45
- try {
46
- const local = await readLocalFiles({ dir: args.dir, listFiles: args.listFiles });
47
- for (const problem of local.problems) output.stderr(`error: ${problem}`);
48
- if (local.problems.length > 0) return 1;
49
- const compiled = await compileAndPrint({ source: { files: local.files }, client, output });
50
- if (!compiled.ok) {
51
- output.stderr("error: the agent did not compile; nothing was published");
52
- return 1;
53
- }
54
- const definition = await client.definitions.get({ definition: args.agent });
55
- const repository = definition.repository;
56
- const kind = repository?.kind ?? DefinitionRepositoryKind.CodeStorage;
57
- const branch = repository?.defaultBranch ?? "main";
58
- let ref;
59
- if (kind === DefinitionRepositoryKind.GitHub) {
60
- ref = args.ref ?? branch;
61
- } else if (kind === DefinitionRepositoryKind.CodeStorage) {
62
- if (args.ref != null) {
63
- output.stderr(
64
- "error: --ref applies to GitHub-backed agents; this agent is published from the checkout"
65
- );
66
- return 1;
67
- }
68
- ref = await commitCheckout({ publish: args, definition, branch, local: local.files });
69
- } else {
70
- output.stderr(`error: ${args.agent} uses a repository kind this CLI does not know`);
71
- return 1;
72
- }
73
- const request = {
74
- definition: definition.id,
75
- ref
76
- };
77
- if (args.note != null) request.note = args.note;
78
- if (args.activate != null) request.activate = args.activate;
79
- const result = await client.definitions.publish(request);
80
- for (const line of publishResultLines(result)) output.stdout(line);
81
- if (args.activate === false)
82
- output.stdout("source-only: the live agent, routes, and schedules are unchanged");
83
- return 0;
84
- } catch (cause) {
85
- for (const line of errorLines(cause)) output.stderr(line);
86
- return 1;
87
- }
88
- };
89
- export {
90
- runPublish
91
- };
92
- //# sourceMappingURL=publish.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/cli/publish.ts"],
4
- "sourcesContent": ["import type { AgentClientIface } from \"../agent-client/client.mjs\";\nimport { isClientError } from \"../agent-client/errors.mjs\";\nimport { DefinitionRepositoryKind, type DefinitionIface } from \"../agent-client/index.mjs\";\nimport { compileAndPrint } from \"./build.mjs\";\nimport { fileChanges, readLocalFiles, type ListFiles } from \"./files.mjs\";\nimport { errorLines, publishResultLines, type OutputIface } from \"./output.mjs\";\n\n// `final agents publish`: compiles the checkout\n// locally, commits it to the agent's default branch, and publishes that\n// commit. A GitHub-backed definition is not committed to; its ref (the\n// default branch unless given) is published as-is.\n\nexport interface PublishArgsIface {\n dir: string;\n // Definition slug or id.\n agent: string;\n // GitHub-backed definitions only.\n ref: string | null;\n message: string;\n note: string | null;\n activate?: boolean;\n client: AgentClientIface;\n listFiles: ListFiles;\n output: OutputIface;\n}\n\n// The default branch's files and head; an empty repository has neither.\nconst remoteFiles = async (args: {\n client: AgentClientIface;\n definition: DefinitionIface;\n branch: string;\n}): Promise<{ commitSha: string | null; files: Record<string, string> }> => {\n try {\n const listing = await args.client.definitions.files({\n definition: args.definition.id,\n ref: args.branch,\n });\n return {\n commitSha: listing.commitSha,\n files: Object.fromEntries(listing.files.map((file) => [file.path, file.content])),\n };\n } catch (cause) {\n if (isClientError(cause) && cause.status === 404) return { commitSha: null, files: {} };\n throw cause;\n }\n};\n\nconst commitCheckout = async (args: {\n publish: PublishArgsIface;\n definition: DefinitionIface;\n branch: string;\n local: Record<string, string>;\n}): Promise<string> => {\n const { client, output, message } = args.publish;\n const remote = await remoteFiles({ client, definition: args.definition, branch: args.branch });\n const changes = fileChanges({ local: args.local, remote: remote.files });\n if (changes.length === 0 && remote.commitSha != null) {\n output.stdout(`no changes; publishing ${args.branch} at ${remote.commitSha}`);\n return remote.commitSha;\n }\n const request: Parameters<AgentClientIface['definitions']['commit']>[0] = {\n definition: args.definition.id,\n files: changes,\n message,\n branch: args.branch,\n };\n // The commit fails if the branch moved since it was read.\n if (remote.commitSha != null) request.parentSha = remote.commitSha;\n const committed = await client.definitions.commit(request);\n const deleted = changes.filter((change) => change.content == null).length;\n output.stdout(\n `committed ${committed.commitSha} to ${committed.branch} (${changes.length - deleted} written, ${deleted} deleted)`,\n );\n return committed.commitSha;\n};\n\nexport const runPublish = async (args: PublishArgsIface): Promise<number> => {\n const { client, output } = args;\n try {\n const local = await readLocalFiles({ dir: args.dir, listFiles: args.listFiles });\n for (const problem of local.problems) output.stderr(`error: ${problem}`);\n if (local.problems.length > 0) return 1;\n\n // What the platform compiles is the committed files, so compile those.\n const compiled = await compileAndPrint({ source: { files: local.files }, client, output });\n if (!compiled.ok) {\n output.stderr('error: the agent did not compile; nothing was published');\n return 1;\n }\n\n const definition = await client.definitions.get({ definition: args.agent });\n const repository = definition.repository;\n const kind = repository?.kind ?? DefinitionRepositoryKind.CodeStorage;\n const branch = repository?.defaultBranch ?? 'main';\n let ref: string;\n if (kind === DefinitionRepositoryKind.GitHub) {\n ref = args.ref ?? branch;\n } else if (kind === DefinitionRepositoryKind.CodeStorage) {\n if (args.ref != null) {\n output.stderr(\n 'error: --ref applies to GitHub-backed agents; this agent is published from the checkout',\n );\n return 1;\n }\n ref = await commitCheckout({ publish: args, definition, branch, local: local.files });\n } else {\n output.stderr(`error: ${args.agent} uses a repository kind this CLI does not know`);\n return 1;\n }\n\n const request: Parameters<AgentClientIface['definitions']['publish']>[0] = {\n definition: definition.id,\n ref,\n };\n if (args.note != null) request.note = args.note;\n if (args.activate != null) request.activate = args.activate;\n const result = await client.definitions.publish(request);\n for (const line of publishResultLines(result)) output.stdout(line);\n if (args.activate === false)\n output.stdout('source-only: the live agent, routes, and schedules are unchanged');\n return 0;\n } catch (cause) {\n for (const line of errorLines(cause)) output.stderr(line);\n return 1;\n }\n};\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,3 +0,0 @@
1
- import type { CompileOptionsIface, CompileResultIface } from '@finalai/agent-definition/compiler';
2
- export declare const compile: (options: CompileOptionsIface) => Promise<CompileResultIface>;
3
- export type { CompatibilityReportIface, CompiledBundleIface, CompileOptionsIface, CompileResultIface, DiagnosticCode, DiagnosticIface, DiagnosticSeverity, HarnessDescriptionContextIface, } from '@finalai/agent-definition/compiler';
@@ -1,58 +0,0 @@
1
- import { fileURLToPath } from "node:url";
2
- const compile = async (options) => {
3
- const finalAuthoringModules = [
4
- "harnesses",
5
- "harnesses/config-fields",
6
- "harnesses/serverless-final",
7
- "harnesses/serverless-pi",
8
- "harnesses/serverless-nanocode-codex",
9
- "harnesses/serverless-nanocode-claude",
10
- "harnesses/remote-pi",
11
- "harnesses/remote-codex",
12
- "harnesses/remote-claude-code",
13
- "harnesses/remote-acp",
14
- "harnesses/local-stdio",
15
- "sandboxes",
16
- "sandboxes/computer",
17
- "sandboxes/device",
18
- "sandboxes/environment",
19
- "connections",
20
- "channels/final",
21
- "channel-factories"
22
- ].map((path) => "@finalai/final-agent-provider/" + path);
23
- const providerModules = {
24
- ...Object.fromEntries(
25
- finalAuthoringModules.map((specifier) => [
26
- specifier,
27
- fileURLToPath(import.meta.resolve(specifier))
28
- ])
29
- ),
30
- "@finalai/agents": fileURLToPath(import.meta.resolve("@finalai/agents/authoring")),
31
- "@finalai/agents/harnesses": fileURLToPath(
32
- import.meta.resolve("@finalai/final-agent-provider/harnesses")
33
- ),
34
- "@finalai/agents/sandboxes": fileURLToPath(
35
- import.meta.resolve("@finalai/final-agent-provider/sandboxes")
36
- ),
37
- "@finalai/agents/channels/final": fileURLToPath(
38
- import.meta.resolve("@finalai/final-agent-provider/channels/final")
39
- ),
40
- ...options.providerModules
41
- };
42
- return (await import("@finalai/agent-definition/compiler")).compile({
43
- defaultFiles: {
44
- "channels/final.ts": "import { finalChannel } from '@finalai/agents/channels/final'; export default finalChannel();"
45
- },
46
- ...options,
47
- providerModules,
48
- installedSandboxProviders: {
49
- computer: "@finalai/final-agent-provider/sandboxes/computer",
50
- device: "@finalai/final-agent-provider/sandboxes/device",
51
- ...options.installedSandboxProviders
52
- }
53
- });
54
- };
55
- export {
56
- compile
57
- };
58
- //# sourceMappingURL=compile.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/compile.ts"],
4
- "sourcesContent": ["import type { CompileOptionsIface, CompileResultIface } from '@finalai/agent-definition/compiler';\nimport { fileURLToPath } from 'node:url';\nexport const compile = async (options: CompileOptionsIface): Promise<CompileResultIface> => {\n const finalAuthoringModules = [\n 'harnesses',\n 'harnesses/config-fields',\n 'harnesses/serverless-final',\n 'harnesses/serverless-pi',\n 'harnesses/serverless-nanocode-codex',\n 'harnesses/serverless-nanocode-claude',\n 'harnesses/remote-pi',\n 'harnesses/remote-codex',\n 'harnesses/remote-claude-code',\n 'harnesses/remote-acp',\n 'harnesses/local-stdio',\n 'sandboxes',\n 'sandboxes/computer',\n 'sandboxes/device',\n 'sandboxes/environment',\n 'connections',\n 'channels/final',\n 'channel-factories',\n ].map((path) => '@finalai/final-agent-provider/' + path);\n const providerModules = {\n ...Object.fromEntries(\n finalAuthoringModules.map((specifier) => [\n specifier,\n fileURLToPath(import.meta.resolve(specifier)),\n ]),\n ),\n '@finalai/agents': fileURLToPath(import.meta.resolve('@finalai/agents/authoring')),\n '@finalai/agents/harnesses': fileURLToPath(\n import.meta.resolve('@finalai/final-agent-provider/harnesses'),\n ),\n '@finalai/agents/sandboxes': fileURLToPath(\n import.meta.resolve('@finalai/final-agent-provider/sandboxes'),\n ),\n '@finalai/agents/channels/final': fileURLToPath(\n import.meta.resolve('@finalai/final-agent-provider/channels/final'),\n ),\n ...options.providerModules,\n };\n return (await import('@finalai/agent-definition/compiler')).compile({\n defaultFiles: {\n 'channels/final.ts':\n \"import { finalChannel } from '@finalai/agents/channels/final'; export default finalChannel();\",\n },\n ...options,\n providerModules,\n installedSandboxProviders: {\n computer: '@finalai/final-agent-provider/sandboxes/computer',\n device: '@finalai/final-agent-provider/sandboxes/device',\n ...options.installedSandboxProviders,\n },\n });\n};\nexport type {\n CompatibilityReportIface,\n CompiledBundleIface,\n CompileOptionsIface,\n CompileResultIface,\n DiagnosticCode,\n DiagnosticIface,\n DiagnosticSeverity,\n HarnessDescriptionContextIface,\n} from '@finalai/agent-definition/compiler';\n"],
5
- "mappings": "AACA,SAAS,qBAAqB;AACvB,MAAM,UAAU,OAAO,YAA8D;AAC1F,QAAM,wBAAwB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,IAAI,CAAC,SAAS,mCAAmC,IAAI;AACvD,QAAM,kBAAkB;AAAA,IACtB,GAAG,OAAO;AAAA,MACR,sBAAsB,IAAI,CAAC,cAAc;AAAA,QACvC;AAAA,QACA,cAAc,YAAY,QAAQ,SAAS,CAAC;AAAA,MAC9C,CAAC;AAAA,IACH;AAAA,IACA,mBAAmB,cAAc,YAAY,QAAQ,2BAA2B,CAAC;AAAA,IACjF,6BAA6B;AAAA,MAC3B,YAAY,QAAQ,yCAAyC;AAAA,IAC/D;AAAA,IACA,6BAA6B;AAAA,MAC3B,YAAY,QAAQ,yCAAyC;AAAA,IAC/D;AAAA,IACA,kCAAkC;AAAA,MAChC,YAAY,QAAQ,8CAA8C;AAAA,IACpE;AAAA,IACA,GAAG,QAAQ;AAAA,EACb;AACA,UAAQ,MAAM,OAAO,oCAAoC,GAAG,QAAQ;AAAA,IAClE,cAAc;AAAA,MACZ,qBACE;AAAA,IACJ;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA,2BAA2B;AAAA,MACzB,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,GAAG,QAAQ;AAAA,IACb;AAAA,EACF,CAAC;AACH;",
6
- "names": []
7
- }
@@ -1,4 +0,0 @@
1
- export type { CompatibilityReportIface, CompiledBundleIface, CompileOptionsIface, CompileResultIface, DiagnosticCode, DiagnosticIface, DiagnosticSeverity, HarnessDescriptionContextIface, } from "./compile.mjs";
2
- export * from "./public.mjs";
3
- import type { CompileOptionsIface, CompileResultIface } from "./compile.mjs";
4
- export declare const compile: (_options: CompileOptionsIface) => Promise<CompileResultIface>;
@@ -1,8 +0,0 @@
1
- export * from "./public.mjs";
2
- const compile = async (_options) => {
3
- throw new Error("Agent directory compilation requires Node.js.");
4
- };
5
- export {
6
- compile
7
- };
8
- //# sourceMappingURL=index.browser.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/index.browser.ts"],
4
- "sourcesContent": ["export type {\n CompatibilityReportIface,\n CompiledBundleIface,\n CompileOptionsIface,\n CompileResultIface,\n DiagnosticCode,\n DiagnosticIface,\n DiagnosticSeverity,\n HarnessDescriptionContextIface,\n} from \"./compile.mjs\";\nexport * from \"./public.mjs\";\nimport type { CompileOptionsIface, CompileResultIface } from \"./compile.mjs\";\n\nexport const compile = async (_options: CompileOptionsIface): Promise<CompileResultIface> => {\n throw new Error('Agent directory compilation requires Node.js.');\n};\n"],
5
- "mappings": "AAUA,cAAc;AAGP,MAAM,UAAU,OAAO,aAA+D;AAC3F,QAAM,IAAI,MAAM,+CAA+C;AACjE;",
6
- "names": []
7
- }
@@ -1,16 +0,0 @@
1
- # Custom harness fleet
2
-
3
- `agent.ts` demonstrates binding an agent to a custom harness fleet. Replace the sample fleet origin with your fleet and implement its API before publishing. The named `acmeFleet` export lets another definition import the same binding.
4
-
5
- The sample fleet uses its own model login. Billing policy is explicit in definition source; Final MCP and other tool credentials remain independently owned at their MCP hosts. The `acme-fleet-key` secret authenticates hosting operations and must be declared and supplied before publication.
6
-
7
- The fleet API contract is:
8
-
9
- - `POST /sessions`: create or recover by `idempotencyKey`, accepting `sessionId`, `region`, `program` and materialized `mcpServers`.
10
- - `POST /sessions/:id/resume`: accept the saved `generation`, `lastSeq` and fresh `mcpServers`, then return an endpoint for the existing session.
11
- - Both return `{ id, generation, wsUrl, token }`. The WebSocket must be on the fleet's origin and speak ACP v2. Session IDs remain stable, generations are nonnegative, and the native runtime preserves running work and open requests through reconnect. Replay must agree with the declared `resumeReplay` capability.
12
- - `POST /sessions/:id/pause`: persist state before parking; retries are idempotent.
13
- - `DELETE /sessions/:id`: accept `generation` and `force`; persist state on graceful close, abort promptly when forced, and succeed for an already closed session.
14
- - `GET /sessions/:id/health`: return `{ ok, detail? }` from the actual runtime state.
15
-
16
- All routes require a bearer hosting secret. Endpoint tokens authorize only the returned ACP session. The fleet must pass the MCP servers through the installed program's public surface, retain its own settings/login, accept prompts while running under its queue policy, and implement the public conformance cases before use. This example supplies every lifecycle callback; it does not provision that external fleet.
@@ -1,154 +0,0 @@
1
- import {
2
- credentials,
3
- defineAgent,
4
- defineHarness,
5
- type AuthoredHarnessEndpointIface,
6
- } from '@finalai/agents';
7
- import { type JsonValue, type SecretReaderIface } from '@finalai/agent-provider';
8
- import * as z from 'zod';
9
-
10
- const FLEET_ORIGIN = 'https://fleet.acme.dev';
11
- const FLEET_SECRET = 'acme-fleet-key';
12
-
13
- type FleetConfig = {
14
- region: string;
15
- apiKeySecret: typeof FLEET_SECRET;
16
- credentials: JsonValue;
17
- };
18
-
19
- interface FleetRequestArgsIface {
20
- secrets: SecretReaderIface;
21
- path: string;
22
- method: 'GET' | 'POST' | 'DELETE';
23
- body?: unknown;
24
- }
25
-
26
- const requestFleet = async (args: FleetRequestArgsIface): Promise<string> => {
27
- const token = await args.secrets.get(FLEET_SECRET);
28
- if (token == null) throw new Error(`Missing secret ${FLEET_SECRET}`);
29
- const response = await fetch(`${FLEET_ORIGIN}${args.path}`, {
30
- method: args.method,
31
- headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' },
32
- body: args.body == null ? undefined : JSON.stringify(args.body),
33
- signal: AbortSignal.timeout(30_000),
34
- });
35
- const text = await response.text();
36
- if (!response.ok) throw new Error(`Fleet request failed (${response.status})`);
37
- return text;
38
- };
39
-
40
- const fleetEndpointSchema = z.object({
41
- id: z.string().min(1),
42
- generation: z.number().int().nonnegative(),
43
- wsUrl: z.url().refine((value) => {
44
- const url = new URL(value);
45
- return url.protocol === 'wss:' && url.host === new URL(FLEET_ORIGIN).host;
46
- }),
47
- token: z.string().min(1),
48
- });
49
-
50
- const endpointFrom = (text: string): AuthoredHarnessEndpointIface => {
51
- const endpoint = fleetEndpointSchema.parse(JSON.parse(text));
52
- return {
53
- ref: { harnessSessionRef: endpoint.id, generation: endpoint.generation },
54
- transport: 'ws',
55
- url: endpoint.wsUrl,
56
- headers: { authorization: `Bearer ${endpoint.token}` },
57
- };
58
- };
59
-
60
- const fleetHealthSchema = z.object({ ok: z.boolean(), detail: z.string().optional() });
61
-
62
- export const acmeFleet = defineHarness<FleetConfig>({
63
- describe: async () => ({
64
- configSchema: {
65
- type: 'object',
66
- properties: {
67
- region: { type: 'string' },
68
- apiKeySecret: { const: FLEET_SECRET },
69
- credentials: { $ref: 'final://schemas/credential-policy' },
70
- },
71
- required: ['region', 'apiKeySecret', 'credentials'],
72
- additionalProperties: false,
73
- },
74
- acp: { transports: ['ws'], mcp: ['http'] },
75
- inference: { kinds: ['harness-owned'], delivery: 'at-open' },
76
- supports: {
77
- observe: false,
78
- resumeReplay: true,
79
- fork: false,
80
- authorMeta: false,
81
- nativeToolPolicy: false,
82
- },
83
- promptWhileRunning: 'queue',
84
- sessionSurvivesDisconnect: true,
85
- }),
86
- open: async ({ sessionId, harnessSessionId, config, mcpServers, secrets }) =>
87
- endpointFrom(
88
- await requestFleet({
89
- secrets,
90
- path: '/sessions',
91
- method: 'POST',
92
- body: {
93
- sessionId,
94
- idempotencyKey: harnessSessionId,
95
- region: config.region,
96
- program: 'claude-code',
97
- mcpServers,
98
- },
99
- }),
100
- ),
101
- resume: async ({ ref, lastSeq, mcpServers, secrets }) =>
102
- endpointFrom(
103
- await requestFleet({
104
- secrets,
105
- path: `/sessions/${encodeURIComponent(ref.harnessSessionRef)}/resume`,
106
- method: 'POST',
107
- body: { generation: ref.generation, lastSeq, mcpServers },
108
- }),
109
- ),
110
- park: async ({ ref, secrets }) => {
111
- await requestFleet({
112
- secrets,
113
- path: `/sessions/${encodeURIComponent(ref.harnessSessionRef)}/pause`,
114
- method: 'POST',
115
- body: { generation: ref.generation },
116
- });
117
- },
118
- close: async ({ ref, secrets, force }) => {
119
- await requestFleet({
120
- secrets,
121
- path: `/sessions/${encodeURIComponent(ref.harnessSessionRef)}`,
122
- method: 'DELETE',
123
- body: { generation: ref.generation, force },
124
- });
125
- },
126
- health: async ({ ref, secrets }) => {
127
- try {
128
- return fleetHealthSchema.parse(
129
- JSON.parse(
130
- await requestFleet({
131
- secrets,
132
- path: `/sessions/${encodeURIComponent(ref.harnessSessionRef)}/health`,
133
- method: 'GET',
134
- }),
135
- ),
136
- );
137
- } catch (cause) {
138
- return { ok: false, detail: cause instanceof Error ? cause.message : String(cause) };
139
- }
140
- },
141
- });
142
-
143
- export default defineAgent({
144
- name: 'Release Scout',
145
- secrets: [FLEET_SECRET],
146
- harness: acmeFleet({
147
- region: 'eu',
148
- apiKeySecret: FLEET_SECRET,
149
- credentials: credentials.chain({
150
- payer: 'agent-owner',
151
- tryInOrder: [credentials.harness()],
152
- }),
153
- }),
154
- });
@@ -1,12 +0,0 @@
1
- # Custom sandbox provider
2
-
3
- This example uses `@finalai/agents` for authoring and
4
- `@finalai/agent-provider/sandbox` for the sandbox implementation. Build it with:
5
-
6
- ```sh
7
- final-agents build ./examples/custom-sandbox
8
- ```
9
-
10
- `sandbox.ts` exports a provider and its named target. `agent.ts` binds file and shell capabilities to that target, with billing explicitly in the harness configuration. The provider exposes file and shell operations through the SDK's streaming handle RPC and MCP adapters.
11
-
12
- The in-memory backend is a small, ephemeral reference implementation with a limited command set. Its files last only while the resumed handle is live. A persistent provider implements these same methods over its backend API: `prepare` returns the preparation artifact, `start` returns serializable backend state, and `resume` reconnects to that state. The SDK contract and conformance tools are available at `@finalai/agent-provider`, `@finalai/agent-provider/sandbox`, and `@finalai/agent-provider/conformance`.
@@ -1,14 +0,0 @@
1
- import { baseTools, credentials, defineAgent } from '@finalai/agents';
2
- import { serverlessPi } from '@finalai/agents/harnesses';
3
- import { scratch } from './sandbox';
4
-
5
- export default defineAgent({
6
- name: 'Scratch agent',
7
- harness: serverlessPi({
8
- credentials: credentials.chain({
9
- payer: 'organization',
10
- tryInOrder: [credentials.platform()],
11
- }),
12
- }),
13
- tools: baseTools({ shell: scratch, files: scratch }),
14
- });
@@ -1,24 +0,0 @@
1
- import { defineSandboxProvider } from '@finalai/agents';
2
- import { createMemorySandbox } from '@finalai/agent-provider/sandbox';
3
-
4
- // An ephemeral reference provider. Persistent providers reconnect to their backend in resume.
5
- const handle = () => ({
6
- sandbox: createMemorySandbox({ cwd: '/workspace' }),
7
- onSandboxStop: async () => {},
8
- onSandboxDelete: async () => {},
9
- onRuntimeShutdown: async () => {},
10
- });
11
-
12
- export const scratchProvider = defineSandboxProvider({
13
- name: 'scratch',
14
- environment: () => ({
15
- artifactKey: async () => 'scratch-v1',
16
- prepare: async () => ({}),
17
- // A memory sandbox runs as soon as it exists.
18
- awaitRunning: async () => {},
19
- start: async () => ({ handle: handle(), state: {} }),
20
- resume: async () => handle(),
21
- }),
22
- });
23
-
24
- export const scratch = scratchProvider.environment();
@@ -1,22 +0,0 @@
1
- import { baseTools, credentials, defineAgent } from '@finalai/agents';
2
- import { serverlessPi } from '@finalai/agents/harnesses';
3
- import { computer } from './sandbox';
4
-
5
- export default defineAgent({
6
- name: 'Release Scout',
7
- description: 'Answers release questions, runs checks, posts the daily digest.',
8
- // Read by tools/lookup_release_notes.ts and channels/github.ts; linear-token
9
- // comes from connections/linear.ts.
10
- secrets: ['github-token', 'github-webhook-secret'],
11
- // Off unless declared; each capability is bound to a named sandbox target.
12
- tools: baseTools({ shell: computer, files: computer }),
13
- harness: serverlessPi({
14
- model: 'gpt-6-sol',
15
- reasoning: 'medium',
16
- credentials: credentials.chain({
17
- payer: 'organization',
18
- tryInOrder: [credentials.apiKey({ owner: 'organization' }), credentials.platform()],
19
- }),
20
- permissionMode: 'ask',
21
- }),
22
- });
@@ -1,27 +0,0 @@
1
- // A helper next to the channel (no default export, so not a channel itself).
2
- export const verifyGithubSignature = async (
3
- request: Request,
4
- body: string,
5
- secret: string | null,
6
- ): Promise<boolean> => {
7
- const signature = request.headers.get('x-hub-signature-256');
8
- if (
9
- secret == null ||
10
- secret.length === 0 ||
11
- signature == null ||
12
- !/^sha256=[a-f0-9]{64}$/i.test(signature)
13
- )
14
- return false;
15
- const digest = Uint8Array.from(signature.slice(7).match(/.{2}/g) ?? [], (byte) =>
16
- Number.parseInt(byte, 16),
17
- );
18
- const encoder = new TextEncoder();
19
- const key = await crypto.subtle.importKey(
20
- 'raw',
21
- encoder.encode(secret),
22
- { name: 'HMAC', hash: 'SHA-256' },
23
- false,
24
- ['verify'],
25
- );
26
- return crypto.subtle.verify('HMAC', key, digest, encoder.encode(body));
27
- };
@@ -1,32 +0,0 @@
1
- import { defineChannel } from '@finalai/agent-provider';
2
- import { verifyGithubSignature } from './github-signature';
3
- export default defineChannel({
4
- name: 'release-events',
5
- config: { secret: 'github-webhook-secret', signatureHeader: 'x-final-signature' },
6
- credentials: { app: null, secrets: ['github-webhook-secret'] },
7
- identity: { kind: 'none' },
8
- places: { kinds: ['webhook'] },
9
- receive: async () => ({ accepted: true }),
10
- routes: [
11
- {
12
- method: 'POST',
13
- path: '/webhook',
14
- handler: async (ctx) => {
15
- const body = await ctx.request.text();
16
- const headers = new Headers(ctx.request.headers);
17
- const signature = headers.get('x-final-signature');
18
- if (signature != null) headers.set('x-hub-signature-256', signature);
19
- if (
20
- !(await verifyGithubSignature(
21
- new Request(ctx.request.url, { headers }),
22
- body,
23
- await ctx.credentials.secret('github-webhook-secret'),
24
- ))
25
- )
26
- return new Response(null, { status: 401 });
27
- await ctx.receive(JSON.parse(body));
28
- return new Response(null, { status: 202 });
29
- },
30
- },
31
- ],
32
- });
@@ -1,9 +0,0 @@
1
- import { defineMcpClientConnection } from '@finalai/agents';
2
- import { always } from '@finalai/agents/approval';
3
-
4
- export default defineMcpClientConnection({
5
- url: 'https://mcp.linear.app/mcp',
6
- // Bearer from the secrets manager; the secret never reaches the harness.
7
- auth: { secretKey: 'linear-token', headerName: null },
8
- tools: { allow: ['search_issues', 'create_issue'], approval: { create_issue: always() } },
9
- });
@@ -1,24 +0,0 @@
1
- import { defineHook } from '@finalai/agents/hooks';
2
- import { toolResultFrom } from '@finalai/agents/tools';
3
- import lookupReleaseNotes from '../tools/lookup_release_notes';
4
-
5
- export default defineHook({
6
- events: {
7
- async 'turn.ended'(event, ctx) {
8
- if (event.data.stopReason === 'error') {
9
- await ctx.final.post({ text: 'Something went wrong on my side; I have logged it.' });
10
- }
11
- },
12
- async tool_call_update(event) {
13
- const notes = toolResultFrom(event, lookupReleaseNotes);
14
- if (notes?.found === false)
15
- console.warn('release notes missing', { tag: event.data.rawInput['tag'] });
16
- },
17
- async '*'(event, ctx) {
18
- await fetch('https://audit.example.com/events', {
19
- method: 'POST',
20
- body: JSON.stringify({ id: event.meta.id, session: ctx.session.id, type: event.type }),
21
- });
22
- },
23
- },
24
- });
@@ -1,26 +0,0 @@
1
- import { defineDynamic } from '@finalai/agents';
2
- import { defineInstructions } from '@finalai/agents/instructions';
3
- import * as z from 'zod';
4
-
5
- const calendarSchema = z.object({ nextRelease: z.string(), onCall: z.string() });
6
-
7
- export default defineDynamic({
8
- // Only needed because the value is unknown until a session starts and Build
9
- // still has to show something in this fragment's slot.
10
- description: "Adds the organization's release calendar and current on-call.",
11
- preview: 'Release calendar: 2.4.1 on 2026-10-10. On-call: @mina.',
12
- events: {
13
- 'session.started': async (_event, ctx) => {
14
- const url = new URL('https://ops.example.com/calendar');
15
- url.searchParams.set('org', ctx.session.organizationId);
16
- const res = await fetch(url);
17
- const text = await res.text();
18
- if (!res.ok) throw new Error(`Release calendar request failed (${res.status})`);
19
- const { nextRelease, onCall } = calendarSchema.parse(JSON.parse(text));
20
- return defineInstructions({
21
- role: 'user',
22
- content: `Release calendar: ${nextRelease}. On-call: ${onCall}.`,
23
- });
24
- },
25
- },
26
- });
@@ -1,2 +0,0 @@
1
- You are Release Scout for the Final engineering team. Be brief. Cite release tags.
2
- When asked to verify something, run it rather than guessing.
@@ -1,20 +0,0 @@
1
- import { defineSandbox } from '@finalai/agents';
2
- import { computerSetupGuide } from '@finalai/agents/sandboxes';
3
-
4
- // A saved guide by reference. Everything after
5
- // ref/version overrides the saved version's defaults.
6
- export const computer = computerSetupGuide({
7
- ref: 'release-scout-dev',
8
- version: 'latest',
9
- repositories: [{ alias: 'app', repository: 'final/app', ref: 'main' }],
10
- variables: ['NPM_TOKEN'],
11
- workspace: 'session',
12
- networkPolicy: 'allow-all',
13
- });
14
-
15
- // The default export opens the target named `computer` for each session.
16
- export default defineSandbox(async ({ session }) => {
17
- const sandbox = await computer.open({ access: 'write' });
18
- await sandbox.writeTextFile({ path: '.final/session', content: session.id });
19
- return sandbox;
20
- });
@@ -1,7 +0,0 @@
1
- ---
2
- cron: '0 9 * * 1-5'
3
- timezone: America/Los_Angeles
4
- target: owner-direct
5
- ---
6
-
7
- Summarize what shipped in the last 24 hours and anything blocking the next release.
@@ -1,8 +0,0 @@
1
- ---
2
- name: triage
3
- description: Triage a failing release check into a Linear issue with owner and severity.
4
- ---
5
-
6
- 1. Reproduce the failure in the computer (`shell`) before filing anything.
7
- 2. Search Linear for an existing issue with `search_issues`.
8
- 3. File with `create_issue` only when nothing matches; include the release tag and the failing command.
@@ -1,3 +0,0 @@
1
- - Release tag
2
- - Failing command and exit code
3
- - First bad commit, if bisected