@finalai/agents 0.6.3 → 0.9.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 (34) hide show
  1. package/HOSTING.md +4 -4
  2. package/README.md +2 -0
  3. package/dist/modules/agent-client/acp.mjs.map +2 -2
  4. package/dist/modules/agent-client/build.d.mts +2 -10
  5. package/dist/modules/agent-client/build.mjs +0 -9
  6. package/dist/modules/agent-client/build.mjs.map +2 -2
  7. package/dist/modules/agent-client/channels.d.mts +23 -0
  8. package/dist/modules/agent-client/channels.mjs +49 -0
  9. package/dist/modules/agent-client/channels.mjs.map +7 -0
  10. package/dist/modules/agent-client/client.d.mts +2 -0
  11. package/dist/modules/agent-client/client.mjs +2 -0
  12. package/dist/modules/agent-client/client.mjs.map +2 -2
  13. package/dist/modules/agent-client/conversations.d.mts +8 -10
  14. package/dist/modules/agent-client/conversations.mjs.map +2 -2
  15. package/dist/modules/agent-client/http.mjs.map +2 -2
  16. package/dist/modules/agent-client/index.d.mts +1 -0
  17. package/dist/modules/agent-client/index.mjs.map +1 -1
  18. package/dist/modules/cli/channel-install.d.mts +10 -0
  19. package/dist/modules/cli/channel-install.mjs +32 -0
  20. package/dist/modules/cli/channel-install.mjs.map +7 -0
  21. package/dist/modules/cli/cli.mjs +23 -1
  22. package/dist/modules/cli/cli.mjs.map +2 -2
  23. package/dist/modules/cli/dev.d.mts +2 -0
  24. package/dist/modules/cli/dev.mjs +70 -8
  25. package/dist/modules/cli/dev.mjs.map +2 -2
  26. package/dist/modules/compile.mjs +7 -0
  27. package/dist/modules/compile.mjs.map +2 -2
  28. package/dist/modules/public.d.mts +2 -2
  29. package/dist/modules/public.mjs +2 -0
  30. package/dist/modules/public.mjs.map +2 -2
  31. package/examples/release-scout/agent/channels/github.ts +2 -38
  32. package/examples/release-scout/agent/hooks/audit.ts +1 -1
  33. package/examples/release-scout/agent/instructions/org-context.ts +1 -1
  34. package/package.json +7 -7
@@ -0,0 +1,32 @@
1
+ import { errorLines } from "./output.mjs";
2
+ const names = ["slack", "discord", "github", "linear"];
3
+ const runChannelInstall = async (args) => {
4
+ const name = names.find(
5
+ (candidate) => args.packageName === `@finalai/${candidate}-channel` || args.packageName === `@finalai/final-agent-provider/channels/${candidate}`
6
+ );
7
+ if (name == null) {
8
+ args.output.stderr(`error: unsupported shared channel ${args.packageName}`);
9
+ return 2;
10
+ }
11
+ try {
12
+ const result = await args.client.channelBindings.create({
13
+ projectId: args.projectId,
14
+ connectorInstallId: args.connectorInstallId,
15
+ channel: { kind: "package", specifier: `@finalai/final-agent-provider/channels/${name}` },
16
+ config: {}
17
+ });
18
+ args.output.stdout(`installed ${name}: ${result.bindingId}`);
19
+ for (const route of result.routes) {
20
+ const url = route.url ?? route.aliasUrl;
21
+ if (url != null) args.output.stdout(` ${route.method} ${url}`);
22
+ }
23
+ return 0;
24
+ } catch (error) {
25
+ for (const line of errorLines(error)) args.output.stderr(line);
26
+ return 1;
27
+ }
28
+ };
29
+ export {
30
+ runChannelInstall
31
+ };
32
+ //# sourceMappingURL=channel-install.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/cli/channel-install.ts"],
4
+ "sourcesContent": ["import type { AgentClientIface } from \"../agent-client/client.mjs\";\nimport { errorLines, type OutputIface } from \"./output.mjs\";\nconst names = ['slack', 'discord', 'github', 'linear'];\nexport interface ChannelInstallArgsIface {\n packageName: string;\n projectId: string;\n connectorInstallId: string;\n client: AgentClientIface;\n output: OutputIface;\n}\nexport const runChannelInstall = async (args: ChannelInstallArgsIface): Promise<number> => {\n const name = names.find(\n (candidate) =>\n args.packageName === `@finalai/${candidate}-channel` ||\n args.packageName === `@finalai/final-agent-provider/channels/${candidate}`,\n );\n if (name == null) {\n args.output.stderr(`error: unsupported shared channel ${args.packageName}`);\n return 2;\n }\n try {\n const result = await args.client.channelBindings.create({\n projectId: args.projectId,\n connectorInstallId: args.connectorInstallId,\n channel: { kind: 'package', specifier: `@finalai/final-agent-provider/channels/${name}` },\n config: {},\n });\n args.output.stdout(`installed ${name}: ${result.bindingId}`);\n for (const route of result.routes) {\n const url = route.url ?? route.aliasUrl;\n if (url != null) args.output.stdout(` ${route.method} ${url}`);\n }\n return 0;\n } catch (error) {\n for (const line of errorLines(error)) args.output.stderr(line);\n return 1;\n }\n};\n"],
5
+ "mappings": "AACA,SAAS,kBAAoC;AAC7C,MAAM,QAAQ,CAAC,SAAS,WAAW,UAAU,QAAQ;AAQ9C,MAAM,oBAAoB,OAAO,SAAmD;AACzF,QAAM,OAAO,MAAM;AAAA,IACjB,CAAC,cACC,KAAK,gBAAgB,YAAY,SAAS,cAC1C,KAAK,gBAAgB,0CAA0C,SAAS;AAAA,EAC5E;AACA,MAAI,QAAQ,MAAM;AAChB,SAAK,OAAO,OAAO,qCAAqC,KAAK,WAAW,EAAE;AAC1E,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,MAAM,KAAK,OAAO,gBAAgB,OAAO;AAAA,MACtD,WAAW,KAAK;AAAA,MAChB,oBAAoB,KAAK;AAAA,MACzB,SAAS,EAAE,MAAM,WAAW,WAAW,0CAA0C,IAAI,GAAG;AAAA,MACxF,QAAQ,CAAC;AAAA,IACX,CAAC;AACD,SAAK,OAAO,OAAO,aAAa,IAAI,KAAK,OAAO,SAAS,EAAE;AAC3D,eAAW,SAAS,OAAO,QAAQ;AACjC,YAAM,MAAM,MAAM,OAAO,MAAM;AAC/B,UAAI,OAAO,KAAM,MAAK,OAAO,OAAO,KAAK,MAAM,MAAM,IAAI,GAAG,EAAE;AAAA,IAChE;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,eAAW,QAAQ,WAAW,KAAK,EAAG,MAAK,OAAO,OAAO,IAAI;AAC7D,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -2,6 +2,7 @@ import { resolve } from "node:path";
2
2
  import { parseArgs } from "node:util";
3
3
  import * as z from "zod";
4
4
  import { createClient } from "../agent-client/client.mjs";
5
+ import { runChannelInstall } from "./channel-install.mjs";
5
6
  import { runBuild } from "./build.mjs";
6
7
  import { runConformance } from "./conformance.mjs";
7
8
  import { DEFAULT_DEV_PORT, runDev } from "./dev.mjs";
@@ -16,6 +17,7 @@ const USAGE = [
16
17
  " build [dir] compile the agent directory and report on its harness",
17
18
  " dev [dir] serve its channel routes at http://localhost:<port>/<channel><path>",
18
19
  " publish [dir] --agent <slug> commit the checkout to the agent and publish it",
20
+ " channel install <package> --project <id> --install <id> install a shared channel",
19
21
  " conformance <module> run the harness conformance kit against a harness the module exports",
20
22
  "",
21
23
  "options:",
@@ -45,6 +47,8 @@ const optionsConfig = {
45
47
  message: { type: "string" },
46
48
  note: { type: "string" },
47
49
  port: { type: "string" },
50
+ project: { type: "string" },
51
+ install: { type: "string" },
48
52
  export: { type: "string" },
49
53
  profile: { type: "string" },
50
54
  timeout: { type: "string" },
@@ -73,7 +77,7 @@ const runAgentsCommand = async (deps) => {
73
77
  (command == null && values.help !== true ? output.stderr : output.stdout)(USAGE);
74
78
  return command == null && values.help !== true ? 2 : 0;
75
79
  }
76
- if (extra.length > 0) {
80
+ if (extra.length > 0 && !(command === "channel" && dirArg === "install" && extra.length === 1)) {
77
81
  output.stderr(`error: unexpected arguments: ${extra.join(" ")}`);
78
82
  return 2;
79
83
  }
@@ -91,6 +95,24 @@ const runAgentsCommand = async (deps) => {
91
95
  auth: { apiKey: key },
92
96
  fetch: deps.fetch
93
97
  });
98
+ if (command === "channel") {
99
+ const packageName = extra[0];
100
+ if (dirArg !== "install" || packageName == null || values.project == null || values.install == null) {
101
+ output.stderr("error: channel install needs <package> --project <id> --install <id>");
102
+ return 2;
103
+ }
104
+ if (apiKey == null) {
105
+ output.stderr("error: set FINAL_API_KEY to a Final API key");
106
+ return 2;
107
+ }
108
+ return runChannelInstall({
109
+ packageName,
110
+ projectId: values.project,
111
+ connectorInstallId: values.install,
112
+ client: client(apiKey),
113
+ output
114
+ });
115
+ }
94
116
  if (command === "build") {
95
117
  return runBuild({ dir, client: apiKey == null ? null : client(apiKey), output });
96
118
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/cli/cli.ts"],
4
- "sourcesContent": ["import { resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport * as z from 'zod';\nimport { createClient, type AgentClientIface } from \"../agent-client/client.mjs\";\nimport type { FetchIface } from \"../agent-client/http.mjs\";\nimport { runBuild } from \"./build.mjs\";\nimport { runConformance, type ImportModule } from \"./conformance.mjs\";\nimport { DEFAULT_DEV_PORT, runDev } from \"./dev.mjs\";\nimport { gitListFiles, type ListFiles } from \"./files.mjs\";\nimport type { OutputIface } from \"./output.mjs\";\nimport { runPublish } from \"./publish.mjs\";\n\n// Agent CLI commands:\n// `build` and `publish`, plus `dev` and `conformance`. Shipped as the `final-agents` bin until a general\n// `final` CLI exists; `runAgentsCommand` is what `final agents` would mount.\n\n// The agents API, authenticated with FINAL_API_KEY.\nexport const DEFAULT_AGENTS_HOST = 'https://agent-session.final.ai/api';\n\nconst DEFAULT_COMMIT_MESSAGE = 'Publish with final agents publish';\n\nconst USAGE = [\n 'usage: final-agents <command> [options]',\n '',\n 'commands:',\n ' build [dir] compile the agent directory and report on its harness',\n ' dev [dir] serve its channel routes at http://localhost:<port>/<channel><path>',\n ' publish [dir] --agent <slug> commit the checkout to the agent and publish it',\n ' conformance <module> run the harness conformance kit against a harness the module exports',\n '',\n 'options:',\n ' --host <url> agent platform API (overrides FINAL_API_HOST; default ' +\n DEFAULT_AGENTS_HOST +\n ')',\n ' --agent <slug> publish: the agent definition (slug or id)',\n ' --ref <ref> publish: the ref to publish (GitHub-backed agents)',\n ' --message <text> publish: commit message',\n ' --note <text> publish: revision note',\n ` --port <port> dev: port to listen on (default ${DEFAULT_DEV_PORT})`,\n ' --export <name> conformance: the export to test (default \"default\"): a HarnessIface or { harness, dial }',\n ' --profile <name> conformance: final (default) or plain-acp-v2',\n ' --timeout <ms> conformance: per-case timeout',\n ' --json conformance: print the report as JSON',\n '',\n 'FINAL_API_KEY authenticates. build checks compatibility only with it.',\n 'FINAL_API_HOST selects the deployment for build and publish; it does not rewrite authored URLs.',\n 'dev reads route secrets from AGENT_LOCAL_SECRETS_JSON ({\"name\": \"value\"}), limited to the manifest\\'s secrets.',\n].join('\\n');\n\nconst envSchema = z.object({\n FINAL_API_KEY: z.string().min(1).optional(),\n FINAL_API_HOST: z.string().url().optional(),\n});\n\nexport interface AgentsCliDepsIface {\n argv: string[];\n env: Record<string, string | undefined>;\n cwd: string;\n output: OutputIface;\n // Seams: API requests and the checkout's file listing.\n fetch?: FetchIface;\n listFiles?: ListFiles;\n // Ends long-running commands (dev); main.ts aborts it on SIGINT and SIGTERM.\n signal?: AbortSignal;\n // Seam: loads the conformance module (dynamic import by file URL).\n importModule?: ImportModule;\n}\n\nconst optionsConfig = {\n host: { type: 'string' },\n agent: { type: 'string' },\n ref: { type: 'string' },\n message: { type: 'string' },\n note: { type: 'string' },\n port: { type: 'string' },\n export: { type: 'string' },\n profile: { type: 'string' },\n timeout: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n} as const;\n\nconst parseCommandLine = (argv: string[]) =>\n parseArgs({ args: argv, options: optionsConfig, allowPositionals: true });\n\ntype ParsedResult =\n | { ok: true; parsed: ReturnType<typeof parseCommandLine> }\n | { ok: false; message: string };\n\nconst parse = (argv: string[]): ParsedResult => {\n try {\n return { ok: true, parsed: parseCommandLine(argv) };\n } catch (cause) {\n return { ok: false, message: cause instanceof Error ? cause.message : String(cause) };\n }\n};\n\nexport const runAgentsCommand = async (deps: AgentsCliDepsIface): Promise<number> => {\n const { output } = deps;\n const parsedArgs = parse(deps.argv);\n if (!parsedArgs.ok) {\n output.stderr(`error: ${parsedArgs.message}`);\n output.stderr(USAGE);\n return 2;\n }\n const { values, positionals } = parsedArgs.parsed;\n const [command, dirArg, ...extra] = positionals;\n if (values.help === true || command == null || command === 'help') {\n (command == null && values.help !== true ? output.stderr : output.stdout)(USAGE);\n return command == null && values.help !== true ? 2 : 0;\n }\n if (extra.length > 0) {\n output.stderr(`error: unexpected arguments: ${extra.join(' ')}`);\n return 2;\n }\n const env = envSchema.safeParse(deps.env);\n if (!env.success) {\n output.stderr(\n 'error: FINAL_API_KEY must be nonempty and FINAL_API_HOST must be an absolute URL',\n );\n return 2;\n }\n const apiKey = env.success ? (env.data.FINAL_API_KEY ?? null) : null;\n const dir = resolve(deps.cwd, dirArg ?? '.');\n const client = (key: string): AgentClientIface =>\n createClient({\n host: values.host ?? env.data.FINAL_API_HOST ?? DEFAULT_AGENTS_HOST,\n auth: { apiKey: key },\n fetch: deps.fetch,\n });\n\n if (command === 'build') {\n return runBuild({ dir, client: apiKey == null ? null : client(apiKey), output });\n }\n if (command === 'dev') {\n const port = values.port == null ? DEFAULT_DEV_PORT : Number(values.port);\n if (!Number.isInteger(port) || port < 0 || port > 65_535) {\n output.stderr(`error: --port must be a port number`);\n return 2;\n }\n return runDev({\n dir,\n port,\n env: deps.env,\n output,\n signal: deps.signal ?? new AbortController().signal,\n });\n }\n if (command === 'publish') {\n if (values.agent == null) {\n output.stderr('error: publish needs --agent <slug>');\n return 2;\n }\n if (apiKey == null) {\n output.stderr('error: set FINAL_API_KEY to a Final API key');\n return 2;\n }\n return runPublish({\n dir,\n agent: values.agent,\n ref: values.ref ?? null,\n message: values.message ?? DEFAULT_COMMIT_MESSAGE,\n note: values.note ?? null,\n client: client(apiKey),\n listFiles: deps.listFiles ?? gitListFiles,\n output,\n });\n }\n if (command === 'conformance') {\n if (dirArg == null) {\n output.stderr('error: conformance needs <module>');\n return 2;\n }\n const timeoutMs = values.timeout == null ? null : Number(values.timeout);\n if (timeoutMs != null && (!Number.isInteger(timeoutMs) || timeoutMs <= 0)) {\n output.stderr('error: --timeout must be a positive number of milliseconds');\n return 2;\n }\n return runConformance({\n module: dirArg,\n exportName: values.export ?? 'default',\n profile: values.profile ?? 'final',\n timeoutMs,\n json: values.json === true,\n cwd: deps.cwd,\n output,\n importModule: deps.importModule,\n signal: deps.signal,\n });\n }\n output.stderr(`error: unknown command ${command}`);\n output.stderr(USAGE);\n return 2;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport * as z from 'zod';\nimport { createClient, type AgentClientIface } from \"../agent-client/client.mjs\";\nimport type { FetchIface } from \"../agent-client/http.mjs\";\nimport { runChannelInstall } from \"./channel-install.mjs\";\nimport { runBuild } from \"./build.mjs\";\nimport { runConformance, type ImportModule } from \"./conformance.mjs\";\nimport { DEFAULT_DEV_PORT, runDev } from \"./dev.mjs\";\nimport { gitListFiles, type ListFiles } from \"./files.mjs\";\nimport type { OutputIface } from \"./output.mjs\";\nimport { runPublish } from \"./publish.mjs\";\n\n// Agent CLI commands:\n// `build` and `publish`, plus `dev` and `conformance`. Shipped as the `final-agents` bin until a general\n// `final` CLI exists; `runAgentsCommand` is what `final agents` would mount.\n\n// The agents API, authenticated with FINAL_API_KEY.\nexport const DEFAULT_AGENTS_HOST = 'https://agent-session.final.ai/api';\n\nconst DEFAULT_COMMIT_MESSAGE = 'Publish with final agents publish';\n\nconst USAGE = [\n 'usage: final-agents <command> [options]',\n '',\n 'commands:',\n ' build [dir] compile the agent directory and report on its harness',\n ' dev [dir] serve its channel routes at http://localhost:<port>/<channel><path>',\n ' publish [dir] --agent <slug> commit the checkout to the agent and publish it',\n ' channel install <package> --project <id> --install <id> install a shared channel',\n ' conformance <module> run the harness conformance kit against a harness the module exports',\n '',\n 'options:',\n ' --host <url> agent platform API (overrides FINAL_API_HOST; default ' +\n DEFAULT_AGENTS_HOST +\n ')',\n ' --agent <slug> publish: the agent definition (slug or id)',\n ' --ref <ref> publish: the ref to publish (GitHub-backed agents)',\n ' --message <text> publish: commit message',\n ' --note <text> publish: revision note',\n ` --port <port> dev: port to listen on (default ${DEFAULT_DEV_PORT})`,\n ' --export <name> conformance: the export to test (default \"default\"): a HarnessIface or { harness, dial }',\n ' --profile <name> conformance: final (default) or plain-acp-v2',\n ' --timeout <ms> conformance: per-case timeout',\n ' --json conformance: print the report as JSON',\n '',\n 'FINAL_API_KEY authenticates. build checks compatibility only with it.',\n 'FINAL_API_HOST selects the deployment for build and publish; it does not rewrite authored URLs.',\n 'dev reads route secrets from AGENT_LOCAL_SECRETS_JSON ({\"name\": \"value\"}), limited to the manifest\\'s secrets.',\n].join('\\n');\n\nconst envSchema = z.object({\n FINAL_API_KEY: z.string().min(1).optional(),\n FINAL_API_HOST: z.string().url().optional(),\n});\n\nexport interface AgentsCliDepsIface {\n argv: string[];\n env: Record<string, string | undefined>;\n cwd: string;\n output: OutputIface;\n // Seams: API requests and the checkout's file listing.\n fetch?: FetchIface;\n listFiles?: ListFiles;\n // Ends long-running commands (dev); main.ts aborts it on SIGINT and SIGTERM.\n signal?: AbortSignal;\n // Seam: loads the conformance module (dynamic import by file URL).\n importModule?: ImportModule;\n}\n\nconst optionsConfig = {\n host: { type: 'string' },\n agent: { type: 'string' },\n ref: { type: 'string' },\n message: { type: 'string' },\n note: { type: 'string' },\n port: { type: 'string' },\n project: { type: 'string' },\n install: { type: 'string' },\n export: { type: 'string' },\n profile: { type: 'string' },\n timeout: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n} as const;\n\nconst parseCommandLine = (argv: string[]) =>\n parseArgs({ args: argv, options: optionsConfig, allowPositionals: true });\n\ntype ParsedResult =\n | { ok: true; parsed: ReturnType<typeof parseCommandLine> }\n | { ok: false; message: string };\n\nconst parse = (argv: string[]): ParsedResult => {\n try {\n return { ok: true, parsed: parseCommandLine(argv) };\n } catch (cause) {\n return { ok: false, message: cause instanceof Error ? cause.message : String(cause) };\n }\n};\n\nexport const runAgentsCommand = async (deps: AgentsCliDepsIface): Promise<number> => {\n const { output } = deps;\n const parsedArgs = parse(deps.argv);\n if (!parsedArgs.ok) {\n output.stderr(`error: ${parsedArgs.message}`);\n output.stderr(USAGE);\n return 2;\n }\n const { values, positionals } = parsedArgs.parsed;\n const [command, dirArg, ...extra] = positionals;\n if (values.help === true || command == null || command === 'help') {\n (command == null && values.help !== true ? output.stderr : output.stdout)(USAGE);\n return command == null && values.help !== true ? 2 : 0;\n }\n if (extra.length > 0 && !(command === 'channel' && dirArg === 'install' && extra.length === 1)) {\n output.stderr(`error: unexpected arguments: ${extra.join(' ')}`);\n return 2;\n }\n const env = envSchema.safeParse(deps.env);\n if (!env.success) {\n output.stderr(\n 'error: FINAL_API_KEY must be nonempty and FINAL_API_HOST must be an absolute URL',\n );\n return 2;\n }\n const apiKey = env.success ? (env.data.FINAL_API_KEY ?? null) : null;\n const dir = resolve(deps.cwd, dirArg ?? '.');\n const client = (key: string): AgentClientIface =>\n createClient({\n host: values.host ?? env.data.FINAL_API_HOST ?? DEFAULT_AGENTS_HOST,\n auth: { apiKey: key },\n fetch: deps.fetch,\n });\n\n if (command === 'channel') {\n const packageName = extra[0];\n if (\n dirArg !== 'install' ||\n packageName == null ||\n values.project == null ||\n values.install == null\n ) {\n output.stderr('error: channel install needs <package> --project <id> --install <id>');\n return 2;\n }\n if (apiKey == null) {\n output.stderr('error: set FINAL_API_KEY to a Final API key');\n return 2;\n }\n return runChannelInstall({\n packageName,\n projectId: values.project,\n connectorInstallId: values.install,\n client: client(apiKey),\n output,\n });\n }\n if (command === 'build') {\n return runBuild({ dir, client: apiKey == null ? null : client(apiKey), output });\n }\n if (command === 'dev') {\n const port = values.port == null ? DEFAULT_DEV_PORT : Number(values.port);\n if (!Number.isInteger(port) || port < 0 || port > 65_535) {\n output.stderr(`error: --port must be a port number`);\n return 2;\n }\n return runDev({\n dir,\n port,\n env: deps.env,\n output,\n signal: deps.signal ?? new AbortController().signal,\n });\n }\n if (command === 'publish') {\n if (values.agent == null) {\n output.stderr('error: publish needs --agent <slug>');\n return 2;\n }\n if (apiKey == null) {\n output.stderr('error: set FINAL_API_KEY to a Final API key');\n return 2;\n }\n return runPublish({\n dir,\n agent: values.agent,\n ref: values.ref ?? null,\n message: values.message ?? DEFAULT_COMMIT_MESSAGE,\n note: values.note ?? null,\n client: client(apiKey),\n listFiles: deps.listFiles ?? gitListFiles,\n output,\n });\n }\n if (command === 'conformance') {\n if (dirArg == null) {\n output.stderr('error: conformance needs <module>');\n return 2;\n }\n const timeoutMs = values.timeout == null ? null : Number(values.timeout);\n if (timeoutMs != null && (!Number.isInteger(timeoutMs) || timeoutMs <= 0)) {\n output.stderr('error: --timeout must be a positive number of milliseconds');\n return 2;\n }\n return runConformance({\n module: dirArg,\n exportName: values.export ?? 'default',\n profile: values.profile ?? 'final',\n timeoutMs,\n json: values.json === true,\n cwd: deps.cwd,\n output,\n importModule: deps.importModule,\n signal: deps.signal,\n });\n }\n output.stderr(`error: unknown command ${command}`);\n output.stderr(USAGE);\n return 2;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { type InstalledAppInfoIface } from '@finalai/agent-provider';
1
2
  import { type OutputIface } from "./output.mjs";
2
3
  export declare const DEFAULT_DEV_PORT = 3000;
3
4
  export declare const parseLocalSecrets: (text: string | undefined) => Record<string, string> | null;
@@ -6,6 +7,7 @@ export interface DevServerArgsIface {
6
7
  port: number;
7
8
  hostname?: string;
8
9
  secrets: Record<string, string>;
10
+ apps?: Record<string, InstalledAppInfoIface>;
9
11
  output: OutputIface;
10
12
  fetch?: typeof fetch;
11
13
  }
@@ -1,9 +1,12 @@
1
+ import { createLocalChannelContext } from "@finalai/agent-provider/local-channel-context";
1
2
  import {
2
3
  DiagnosticSeverity,
3
4
  hasErrors,
4
5
  loadBundleInLocalIsolate
5
6
  } from "@finalai/agent-definition/compiler";
6
- import { ProviderRefKind } from "@finalai/agent-provider";
7
+ import {
8
+ ProviderRefKind
9
+ } from "@finalai/agent-provider";
7
10
  import { openChannelSocket } from "@finalai/agent-provider/local-channel-socket";
8
11
  import { watch } from "node:fs";
9
12
  import { createServer } from "node:http";
@@ -23,6 +26,12 @@ const parseLocalSecrets = (text) => {
23
26
  return null;
24
27
  }
25
28
  };
29
+ const previewInput = (input) => JSON.stringify(
30
+ input,
31
+ (key, value) => /^(?:token|access_token|refresh_token|id_token|client_secret|clientSecret|signingSecret|authorization|response_url)$/i.test(
32
+ key
33
+ ) ? "[redacted]" : value
34
+ );
26
35
  const readBody = async (request) => {
27
36
  const chunks = [];
28
37
  for await (const chunk of request) chunks.push(Buffer.from(chunk));
@@ -59,7 +68,7 @@ const splitPath = (pathname) => {
59
68
  return { stem: decodeURIComponent(match[1]), path: match[2] ?? "/" };
60
69
  };
61
70
  const loadAgent = async (args) => {
62
- const result = await compile({ dir: args.dir });
71
+ const result = await compile({ dir: args.dir, previewBundle: true });
63
72
  for (const item of result.diagnostics) {
64
73
  (item.severity === DiagnosticSeverity.Error ? args.output.stderr : args.output.stdout)(
65
74
  diagnosticLine(item)
@@ -73,9 +82,11 @@ const loadAgent = async (args) => {
73
82
  const channels = /* @__PURE__ */ new Map();
74
83
  const routes = [];
75
84
  for (const binding of result.manifest.channels) {
76
- if (binding.channel.kind !== ProviderRefKind.Bundle) continue;
77
- channels.set(binding.key, binding.channel.export);
78
- for (const route of result.bundle?.channelRoutes[binding.channel.export] ?? []) {
85
+ const source = result.manifest.channelSources?.[binding.key]?.path;
86
+ const exportName = binding.channel.kind === ProviderRefKind.Bundle ? binding.channel.export : source?.replace(/\.[cm]?[jt]sx?$/, "");
87
+ if (exportName == null) continue;
88
+ channels.set(binding.key, exportName);
89
+ for (const route of binding.surface.routes) {
79
90
  routes.push({ stem: binding.key, method: route.method, path: route.path });
80
91
  }
81
92
  }
@@ -116,8 +127,21 @@ const startDevServer = async (args) => {
116
127
  }
117
128
  const allowed = new Set(current.manifest.secrets);
118
129
  const stem = target.stem;
130
+ const appName = current.manifest.channels.find((binding) => binding.key === stem)?.credentials.app;
119
131
  const response = await current.bundle.runtime.handleChannelRoute({
120
132
  export: exportName,
133
+ context: createLocalChannelContext({
134
+ appInfo: appName == null || args.apps == null || !Object.hasOwn(args.apps, appName) ? void 0 : args.apps[appName],
135
+ secret: async (name) => {
136
+ if (!allowed.has(name)) {
137
+ output.stderr(
138
+ `credentials.secret(${JSON.stringify(name)}): not in the manifest's secrets`
139
+ );
140
+ return null;
141
+ }
142
+ return args.secrets[name] ?? null;
143
+ }
144
+ }),
121
145
  request: await toRequest(request, origin),
122
146
  path: target.path,
123
147
  secrets: {
@@ -130,7 +154,7 @@ const startDevServer = async (args) => {
130
154
  }
131
155
  },
132
156
  receive: async (input) => {
133
- output.stdout(`receive (${stem}): ${JSON.stringify(input)}`);
157
+ output.stdout(`receive (${stem}): ${previewInput(input)}`);
134
158
  return { conversationId: "local" };
135
159
  }
136
160
  });
@@ -160,6 +184,7 @@ const startDevServer = async (args) => {
160
184
  response: new Response("No custom channel socket route", { status: 404 })
161
185
  };
162
186
  const bundle = current.bundle;
187
+ const appName = current.manifest.channels.find((binding) => binding.key === target.stem)?.credentials.app;
163
188
  const allowed = new Set(current.manifest.secrets);
164
189
  const request = new Request(await toRequest(incoming, origin), { signal });
165
190
  return openChannelSocket({
@@ -170,13 +195,25 @@ const startDevServer = async (args) => {
170
195
  get: async (name) => allowed.has(name) ? args.secrets[name] ?? null : null
171
196
  },
172
197
  receive: async (input) => {
173
- output.stdout(`receive (${target.stem}): ${JSON.stringify(input)}`);
198
+ output.stdout(`receive (${target.stem}): ${previewInput(input)}`);
174
199
  return { conversationId: "local" };
175
200
  }
176
201
  },
177
202
  handler: async (ctx) => {
178
203
  const response = await bundle.runtime.handleChannelSocket({
179
204
  export: exportName,
205
+ context: createLocalChannelContext({
206
+ appInfo: appName == null || args.apps == null || !Object.hasOwn(args.apps, appName) ? void 0 : args.apps[appName],
207
+ secret: async (name) => {
208
+ if (!allowed.has(name)) {
209
+ output.stderr(
210
+ `credentials.secret(${JSON.stringify(name)}): not in the manifest's secrets`
211
+ );
212
+ return null;
213
+ }
214
+ return args.secrets[name] ?? null;
215
+ }
216
+ }),
180
217
  path: target.path,
181
218
  ...ctx
182
219
  });
@@ -222,9 +259,34 @@ const runDev = async (args) => {
222
259
  args.output.stderr("error: AGENT_LOCAL_SECRETS_JSON must be a JSON object of name \u2192 value");
223
260
  return 2;
224
261
  }
262
+ let apps = {};
263
+ const metadata = args.env["AGENT_LOCAL_APP_INFO_JSON"];
264
+ if (metadata != null) {
265
+ try {
266
+ apps = z.record(
267
+ z.string().min(1),
268
+ z.object({
269
+ clientId: z.string(),
270
+ clientSecret: z.string(),
271
+ signingSecret: z.string().optional()
272
+ })
273
+ ).parse(JSON.parse(metadata));
274
+ } catch {
275
+ args.output.stderr(
276
+ "error: AGENT_LOCAL_APP_INFO_JSON must map app names to OAuth/signing metadata"
277
+ );
278
+ return 2;
279
+ }
280
+ }
225
281
  let server;
226
282
  try {
227
- server = await startDevServer({ dir: args.dir, port: args.port, secrets, output: args.output });
283
+ server = await startDevServer({
284
+ dir: args.dir,
285
+ port: args.port,
286
+ secrets,
287
+ apps,
288
+ output: args.output
289
+ });
228
290
  } catch (cause) {
229
291
  args.output.stderr(`error: ${cause instanceof Error ? cause.message : String(cause)}`);
230
292
  return 1;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/cli/dev.ts"],
4
- "sourcesContent": ["import {\n DiagnosticSeverity,\n hasErrors,\n loadBundleInLocalIsolate,\n type LoadedBundleIface,\n} from '@finalai/agent-definition/compiler';\nimport { ProviderRefKind, type AgentManifestIface, type JsonValue } from '@finalai/agent-provider';\nimport { openChannelSocket } from '@finalai/agent-provider/local-channel-socket';\nimport { watch, type FSWatcher } from 'node:fs';\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport * as z from 'zod';\nimport { compile } from \"../compile.mjs\";\nimport { attachDevChannelSockets } from \"./channel-socket.mjs\";\nimport { diagnosticLine, type OutputIface } from \"./output.mjs\";\n\n// `final agents dev`: serves the agent's custom channel\n// routes at http://localhost:<port>/<channel-stem><path>, the local\n// counterpart of https://agents.final.ai/<org>/<agent>/<channel-stem><path>.\n// Routes run in a local stand-in for the Worker isolate (a realm with Worker\n// globals only). There is no platform behind it: `receive` prints what the\n// route would deliver, and `secrets.get` reads AGENT_LOCAL_SECRETS_JSON,\n// limited to the manifest's secrets. Edits recompile and swap the bundle.\n\nexport const DEFAULT_DEV_PORT = 3000;\n\nconst localSecretsSchema = z.record(z.string(), z.string());\n\n// node:http's address() for a TCP listener.\nconst listeningAddressSchema = z.object({ port: z.number() });\n\nexport const parseLocalSecrets = (text: string | undefined): Record<string, string> | null => {\n if (text == null || text.length === 0) return {};\n try {\n const parsed = localSecretsSchema.safeParse(JSON.parse(text));\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n};\n\ninterface LoadedAgentIface {\n manifest: AgentManifestIface;\n bundle: LoadedBundleIface | null;\n // Channel stem \u2192 bundle export, for the custom channels the bundle serves.\n channels: Map<string, string>;\n routes: { stem: string; method: string; path: string }[];\n}\n\nexport interface DevServerArgsIface {\n dir: string;\n port: number;\n hostname?: string;\n secrets: Record<string, string>;\n output: OutputIface;\n // The isolate realm's fetch (tests).\n fetch?: typeof fetch;\n}\n\nexport interface DevServerIface {\n url: string;\n // Recompiles; false (and the previous bundle kept) when the compile fails.\n reload(): Promise<boolean>;\n close(): Promise<void>;\n}\n\nconst readBody = async (request: IncomingMessage): Promise<Buffer> => {\n const chunks: Buffer[] = [];\n for await (const chunk of request) chunks.push(Buffer.from(chunk));\n return Buffer.concat(chunks);\n};\n\nconst toRequest = async (request: IncomingMessage, origin: string): Promise<Request> => {\n const method = request.method ?? 'GET';\n const headers = new Headers();\n for (const [name, value] of Object.entries(request.headers)) {\n if (value == null) continue;\n for (const item of Array.isArray(value) ? value : [value]) headers.append(name, item);\n }\n const body = method === 'GET' || method === 'HEAD' ? null : await readBody(request);\n return new Request(new URL(request.url ?? '/', origin), {\n method,\n headers,\n body: body == null || body.byteLength === 0 ? null : new Uint8Array(body),\n });\n};\n\nconst writeResponse = async (response: Response, out: ServerResponse): Promise<void> => {\n out.statusCode = response.status;\n response.headers.forEach((value, name) => out.setHeader(name, value));\n out.end(Buffer.from(await response.arrayBuffer()));\n};\n\nconst plain = (out: ServerResponse, status: number, text: string): void => {\n out.statusCode = status;\n out.setHeader('content-type', 'text/plain; charset=utf-8');\n out.end(`${text}\\n`);\n};\n\n// `/<stem><path>`: the first segment names the channel, the rest is its route path.\nconst splitPath = (pathname: string): { stem: string; path: string } | null => {\n const match = /^\\/([^/]+)(\\/.*)?$/.exec(pathname);\n if (match?.[1] == null) return null;\n return { stem: decodeURIComponent(match[1]), path: match[2] ?? '/' };\n};\n\nconst loadAgent = async (args: {\n dir: string;\n output: OutputIface;\n fetch?: typeof fetch;\n}): Promise<LoadedAgentIface | null> => {\n const result = await compile({ dir: args.dir });\n for (const item of result.diagnostics) {\n (item.severity === DiagnosticSeverity.Error ? args.output.stderr : args.output.stdout)(\n diagnosticLine(item),\n );\n }\n if (hasErrors(result.diagnostics) || result.manifest == null) return null;\n const bundle =\n result.bundle == null\n ? null\n : await loadBundleInLocalIsolate(\n result.bundle.code,\n args.fetch == null ? {} : { fetch: args.fetch },\n );\n const channels = new Map<string, string>();\n const routes: LoadedAgentIface['routes'] = [];\n for (const binding of result.manifest.channels) {\n if (binding.channel.kind !== ProviderRefKind.Bundle) continue;\n channels.set(binding.key, binding.channel.export);\n for (const route of result.bundle?.channelRoutes[binding.channel.export] ?? []) {\n routes.push({ stem: binding.key, method: route.method, path: route.path });\n }\n }\n return { manifest: result.manifest, bundle, channels, routes };\n};\n\nexport const startDevServer = async (args: DevServerArgsIface): Promise<DevServerIface> => {\n const { output } = args;\n let agent: LoadedAgentIface | null = null;\n let origin = '';\n\n const printRoutes = (): void => {\n if (agent == null) return;\n if (agent.routes.length === 0) {\n output.stdout('no custom channel routes (channels/*.ts) to serve');\n return;\n }\n for (const route of agent.routes) {\n output.stdout(` ${route.method} ${origin}/${route.stem}${route.path}`);\n }\n };\n\n const reload = async (): Promise<boolean> => {\n const next = await loadAgent({ dir: args.dir, output, fetch: args.fetch });\n if (next == null) {\n output.stderr(\n agent == null ? 'compile failed' : 'compile failed; still serving the last bundle',\n );\n return false;\n }\n agent = next;\n return true;\n };\n\n const handle = async (request: IncomingMessage, out: ServerResponse): Promise<void> => {\n const current = agent;\n const target = splitPath(new URL(request.url ?? '/', origin).pathname);\n const exportName = target == null ? null : (current?.channels.get(target.stem) ?? null);\n if (current?.bundle == null || target == null || exportName == null) {\n plain(out, 404, 'no custom channel route here');\n return;\n }\n const allowed = new Set(current.manifest.secrets);\n const stem = target.stem;\n const response = await current.bundle.runtime.handleChannelRoute({\n export: exportName,\n request: await toRequest(request, origin),\n path: target.path,\n secrets: {\n get: async (name) => {\n if (!allowed.has(name)) {\n output.stderr(`secrets.get(${JSON.stringify(name)}): not in the manifest's secrets`);\n return null;\n }\n return args.secrets[name] ?? null;\n },\n },\n receive: async (input: JsonValue) => {\n output.stdout(`receive (${stem}): ${JSON.stringify(input)}`);\n return { conversationId: 'local' };\n },\n });\n if (response == null) {\n plain(out, 404, `no ${request.method ?? 'GET'} ${target.path} route on channel ${stem}`);\n return;\n }\n await writeResponse(response, out);\n };\n\n const server = createServer((request, out) => {\n handle(request, out).catch((cause: unknown) => {\n output.stderr(`route failed: ${cause instanceof Error ? cause.message : String(cause)}`);\n if (!out.headersSent) plain(out, 500, 'route failed');\n else out.end();\n });\n });\n const channelSockets = attachDevChannelSockets({\n server,\n log: output.stderr,\n open: async (incoming, signal) => {\n const current = agent;\n const target = splitPath(new URL(incoming.url ?? '/', origin).pathname);\n const exportName = target == null ? null : current?.channels.get(target.stem);\n if (current?.bundle == null || target == null || exportName == null)\n return {\n ok: false,\n response: new Response('No custom channel socket route', { status: 404 }),\n };\n const bundle = current.bundle;\n const allowed = new Set(current.manifest.secrets);\n const request = new Request(await toRequest(incoming, origin), { signal });\n return openChannelSocket({\n signal,\n context: {\n request,\n secrets: {\n get: async (name) => (allowed.has(name) ? (args.secrets[name] ?? null) : null),\n },\n receive: async (input) => {\n output.stdout(`receive (${target.stem}): ${JSON.stringify(input)}`);\n return { conversationId: 'local' };\n },\n },\n handler: async (ctx) => {\n const response = await bundle.runtime.handleChannelSocket({\n export: exportName,\n path: target.path,\n ...ctx,\n });\n return response === null\n ? new Response('No custom channel socket route', { status: 404 })\n : response;\n },\n });\n },\n });\n const hostname = args.hostname ?? 'localhost';\n await new Promise<void>((done, fail) => {\n server.once('error', fail);\n server.listen(args.port, hostname, () => {\n server.off('error', fail);\n done();\n });\n });\n const port = listeningAddressSchema.safeParse(server.address()).data?.port ?? args.port;\n origin = `http://${hostname}:${port}`;\n await reload();\n output.stdout(`serving ${args.dir} at ${origin}`);\n printRoutes();\n\n return {\n url: origin,\n reload: async () => {\n const ok = await reload();\n if (ok) printRoutes();\n return ok;\n },\n close: async () => {\n await channelSockets.close();\n await new Promise<void>((done) => {\n server.closeAllConnections();\n server.close(() => done());\n });\n },\n };\n};\n\nconst RECOMPILE_DEBOUNCE_MS = 150;\n\nconst isBuildOutput = (path: string): boolean =>\n path.startsWith('.final') || path.split(/[\\\\/]/).includes('node_modules');\n\nexport const runDev = async (args: {\n dir: string;\n port: number;\n env: Record<string, string | undefined>;\n output: OutputIface;\n signal: AbortSignal;\n}): Promise<number> => {\n const secrets = parseLocalSecrets(args.env['AGENT_LOCAL_SECRETS_JSON']);\n if (secrets == null) {\n args.output.stderr('error: AGENT_LOCAL_SECRETS_JSON must be a JSON object of name \u2192 value');\n return 2;\n }\n let server: DevServerIface;\n try {\n server = await startDevServer({ dir: args.dir, port: args.port, secrets, output: args.output });\n } catch (cause) {\n args.output.stderr(`error: ${cause instanceof Error ? cause.message : String(cause)}`);\n return 1;\n }\n let timer: ReturnType<typeof setTimeout> | null = null;\n let watcher: FSWatcher | null = null;\n try {\n watcher = watch(args.dir, { recursive: true }, (_event, file) => {\n if (file != null && isBuildOutput(file)) return;\n if (timer != null) clearTimeout(timer);\n timer = setTimeout(() => {\n args.output.stdout('change detected; recompiling');\n void server.reload();\n }, RECOMPILE_DEBOUNCE_MS);\n });\n } catch (cause) {\n args.output.stderr(\n `not watching for changes: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n await new Promise<void>((done) => {\n if (args.signal.aborted) done();\n else args.signal.addEventListener('abort', () => done(), { once: true });\n });\n if (timer != null) clearTimeout(timer);\n watcher?.close();\n await server.close();\n return 0;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createLocalChannelContext } from '@finalai/agent-provider/local-channel-context';\nimport {\n DiagnosticSeverity,\n hasErrors,\n loadBundleInLocalIsolate,\n type LoadedBundleIface,\n} from '@finalai/agent-definition/compiler';\nimport {\n ProviderRefKind,\n type AgentManifestIface,\n type JsonValue,\n type InstalledAppInfoIface,\n} from '@finalai/agent-provider';\nimport { openChannelSocket } from '@finalai/agent-provider/local-channel-socket';\nimport { watch, type FSWatcher } from 'node:fs';\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport * as z from 'zod';\nimport { compile } from \"../compile.mjs\";\nimport { attachDevChannelSockets } from \"./channel-socket.mjs\";\nimport { diagnosticLine, type OutputIface } from \"./output.mjs\";\n\n// Local HTTP and WebSocket previews serve declared channel routes.\n// Routes run in a local stand-in for the Worker isolate (a realm with Worker\n// globals only). There is no platform behind it: `receive` prints what the\n// route would deliver, and `secrets.get` reads AGENT_LOCAL_SECRETS_JSON,\n// limited to the manifest's secrets. Edits recompile and swap the bundle.\n\nexport const DEFAULT_DEV_PORT = 3000;\n\nconst localSecretsSchema = z.record(z.string(), z.string());\n\n// node:http's address() for a TCP listener.\nconst listeningAddressSchema = z.object({ port: z.number() });\n\nexport const parseLocalSecrets = (text: string | undefined): Record<string, string> | null => {\n if (text == null || text.length === 0) return {};\n try {\n const parsed = localSecretsSchema.safeParse(JSON.parse(text));\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n};\n\nconst previewInput = (input: JsonValue): string =>\n JSON.stringify(input, (key, value: unknown) =>\n /^(?:token|access_token|refresh_token|id_token|client_secret|clientSecret|signingSecret|authorization|response_url)$/i.test(\n key,\n )\n ? '[redacted]'\n : value,\n );\n\ninterface LoadedAgentIface {\n manifest: AgentManifestIface;\n bundle: LoadedBundleIface | null;\n // Channel stem \u2192 bundle export, for the custom channels the bundle serves.\n channels: Map<string, string>;\n routes: { stem: string; method: string; path: string }[];\n}\n\nexport interface DevServerArgsIface {\n dir: string;\n port: number;\n hostname?: string;\n secrets: Record<string, string>;\n apps?: Record<string, InstalledAppInfoIface>;\n output: OutputIface;\n // The isolate realm's fetch (tests).\n fetch?: typeof fetch;\n}\n\nexport interface DevServerIface {\n url: string;\n // Recompiles; false (and the previous bundle kept) when the compile fails.\n reload(): Promise<boolean>;\n close(): Promise<void>;\n}\n\nconst readBody = async (request: IncomingMessage): Promise<Buffer> => {\n const chunks: Buffer[] = [];\n for await (const chunk of request) chunks.push(Buffer.from(chunk));\n return Buffer.concat(chunks);\n};\n\nconst toRequest = async (request: IncomingMessage, origin: string): Promise<Request> => {\n const method = request.method ?? 'GET';\n const headers = new Headers();\n for (const [name, value] of Object.entries(request.headers)) {\n if (value == null) continue;\n for (const item of Array.isArray(value) ? value : [value]) headers.append(name, item);\n }\n const body = method === 'GET' || method === 'HEAD' ? null : await readBody(request);\n return new Request(new URL(request.url ?? '/', origin), {\n method,\n headers,\n body: body == null || body.byteLength === 0 ? null : new Uint8Array(body),\n });\n};\n\nconst writeResponse = async (response: Response, out: ServerResponse): Promise<void> => {\n out.statusCode = response.status;\n response.headers.forEach((value, name) => out.setHeader(name, value));\n out.end(Buffer.from(await response.arrayBuffer()));\n};\n\nconst plain = (out: ServerResponse, status: number, text: string): void => {\n out.statusCode = status;\n out.setHeader('content-type', 'text/plain; charset=utf-8');\n out.end(`${text}\\n`);\n};\n\n// `/<stem><path>`: the first segment names the channel, the rest is its route path.\nconst splitPath = (pathname: string): { stem: string; path: string } | null => {\n const match = /^\\/([^/]+)(\\/.*)?$/.exec(pathname);\n if (match?.[1] == null) return null;\n return { stem: decodeURIComponent(match[1]), path: match[2] ?? '/' };\n};\n\nconst loadAgent = async (args: {\n dir: string;\n output: OutputIface;\n fetch?: typeof fetch;\n}): Promise<LoadedAgentIface | null> => {\n const result = await compile({ dir: args.dir, previewBundle: true });\n for (const item of result.diagnostics) {\n (item.severity === DiagnosticSeverity.Error ? args.output.stderr : args.output.stdout)(\n diagnosticLine(item),\n );\n }\n if (hasErrors(result.diagnostics) || result.manifest == null) return null;\n const bundle =\n result.bundle == null\n ? null\n : await loadBundleInLocalIsolate(\n result.bundle.code,\n args.fetch == null ? {} : { fetch: args.fetch },\n );\n const channels = new Map<string, string>();\n const routes: LoadedAgentIface['routes'] = [];\n for (const binding of result.manifest.channels) {\n const source = result.manifest.channelSources?.[binding.key]?.path;\n const exportName =\n binding.channel.kind === ProviderRefKind.Bundle\n ? binding.channel.export\n : source?.replace(/\\.[cm]?[jt]sx?$/, '');\n if (exportName == null) continue;\n channels.set(binding.key, exportName);\n for (const route of binding.surface.routes) {\n routes.push({ stem: binding.key, method: route.method, path: route.path });\n }\n }\n return { manifest: result.manifest, bundle, channels, routes };\n};\n\nexport const startDevServer = async (args: DevServerArgsIface): Promise<DevServerIface> => {\n const { output } = args;\n let agent: LoadedAgentIface | null = null;\n let origin = '';\n\n const printRoutes = (): void => {\n if (agent == null) return;\n if (agent.routes.length === 0) {\n output.stdout('no custom channel routes (channels/*.ts) to serve');\n return;\n }\n for (const route of agent.routes) {\n output.stdout(` ${route.method} ${origin}/${route.stem}${route.path}`);\n }\n };\n\n const reload = async (): Promise<boolean> => {\n const next = await loadAgent({ dir: args.dir, output, fetch: args.fetch });\n if (next == null) {\n output.stderr(\n agent == null ? 'compile failed' : 'compile failed; still serving the last bundle',\n );\n return false;\n }\n agent = next;\n return true;\n };\n\n const handle = async (request: IncomingMessage, out: ServerResponse): Promise<void> => {\n const current = agent;\n const target = splitPath(new URL(request.url ?? '/', origin).pathname);\n const exportName = target == null ? null : (current?.channels.get(target.stem) ?? null);\n if (current?.bundle == null || target == null || exportName == null) {\n plain(out, 404, 'no custom channel route here');\n return;\n }\n const allowed = new Set(current.manifest.secrets);\n const stem = target.stem;\n const appName = current.manifest.channels.find((binding) => binding.key === stem)?.credentials\n .app;\n const response = await current.bundle.runtime.handleChannelRoute({\n export: exportName,\n context: createLocalChannelContext({\n appInfo:\n appName == null || args.apps == null || !Object.hasOwn(args.apps, appName)\n ? undefined\n : args.apps[appName],\n secret: async (name) => {\n if (!allowed.has(name)) {\n output.stderr(\n `credentials.secret(${JSON.stringify(name)}): not in the manifest's secrets`,\n );\n return null;\n }\n return args.secrets[name] ?? null;\n },\n }),\n request: await toRequest(request, origin),\n path: target.path,\n secrets: {\n get: async (name) => {\n if (!allowed.has(name)) {\n output.stderr(`secrets.get(${JSON.stringify(name)}): not in the manifest's secrets`);\n return null;\n }\n return args.secrets[name] ?? null;\n },\n },\n receive: async (input: JsonValue) => {\n output.stdout(`receive (${stem}): ${previewInput(input)}`);\n return { conversationId: 'local' };\n },\n });\n if (response == null) {\n plain(out, 404, `no ${request.method ?? 'GET'} ${target.path} route on channel ${stem}`);\n return;\n }\n await writeResponse(response, out);\n };\n\n const server = createServer((request, out) => {\n handle(request, out).catch((cause: unknown) => {\n output.stderr(`route failed: ${cause instanceof Error ? cause.message : String(cause)}`);\n if (!out.headersSent) plain(out, 500, 'route failed');\n else out.end();\n });\n });\n const channelSockets = attachDevChannelSockets({\n server,\n log: output.stderr,\n open: async (incoming, signal) => {\n const current = agent;\n const target = splitPath(new URL(incoming.url ?? '/', origin).pathname);\n const exportName = target == null ? null : current?.channels.get(target.stem);\n if (current?.bundle == null || target == null || exportName == null)\n return {\n ok: false,\n response: new Response('No custom channel socket route', { status: 404 }),\n };\n const bundle = current.bundle;\n const appName = current.manifest.channels.find((binding) => binding.key === target.stem)\n ?.credentials.app;\n const allowed = new Set(current.manifest.secrets);\n const request = new Request(await toRequest(incoming, origin), { signal });\n return openChannelSocket({\n signal,\n context: {\n request,\n secrets: {\n get: async (name: string) => (allowed.has(name) ? (args.secrets[name] ?? null) : null),\n },\n receive: async (input: import('@finalai/agent-provider').JsonValue) => {\n output.stdout(`receive (${target.stem}): ${previewInput(input)}`);\n return { conversationId: 'local' };\n },\n },\n handler: async (ctx) => {\n const response = await bundle.runtime.handleChannelSocket({\n export: exportName,\n context: createLocalChannelContext({\n appInfo:\n appName == null || args.apps == null || !Object.hasOwn(args.apps, appName)\n ? undefined\n : args.apps[appName],\n secret: async (name) => {\n if (!allowed.has(name)) {\n output.stderr(\n `credentials.secret(${JSON.stringify(name)}): not in the manifest's secrets`,\n );\n return null;\n }\n return args.secrets[name] ?? null;\n },\n }),\n path: target.path,\n ...ctx,\n });\n return response === null\n ? new Response('No custom channel socket route', { status: 404 })\n : response;\n },\n });\n },\n });\n const hostname = args.hostname ?? 'localhost';\n await new Promise<void>((done, fail) => {\n server.once('error', fail);\n server.listen(args.port, hostname, () => {\n server.off('error', fail);\n done();\n });\n });\n const port = listeningAddressSchema.safeParse(server.address()).data?.port ?? args.port;\n origin = `http://${hostname}:${port}`;\n await reload();\n output.stdout(`serving ${args.dir} at ${origin}`);\n printRoutes();\n\n return {\n url: origin,\n reload: async () => {\n const ok = await reload();\n if (ok) printRoutes();\n return ok;\n },\n close: async () => {\n await channelSockets.close();\n await new Promise<void>((done) => {\n server.closeAllConnections();\n server.close(() => done());\n });\n },\n };\n};\n\nconst RECOMPILE_DEBOUNCE_MS = 150;\n\nconst isBuildOutput = (path: string): boolean =>\n path.startsWith('.final') || path.split(/[\\\\/]/).includes('node_modules');\n\nexport const runDev = async (args: {\n dir: string;\n port: number;\n env: Record<string, string | undefined>;\n output: OutputIface;\n signal: AbortSignal;\n}): Promise<number> => {\n const secrets = parseLocalSecrets(args.env['AGENT_LOCAL_SECRETS_JSON']);\n if (secrets == null) {\n args.output.stderr('error: AGENT_LOCAL_SECRETS_JSON must be a JSON object of name \u2192 value');\n return 2;\n }\n let apps: Record<string, InstalledAppInfoIface> = {};\n const metadata = args.env['AGENT_LOCAL_APP_INFO_JSON'];\n if (metadata != null) {\n try {\n apps = z\n .record(\n z.string().min(1),\n z.object({\n clientId: z.string(),\n clientSecret: z.string(),\n signingSecret: z.string().optional(),\n }),\n )\n .parse(JSON.parse(metadata));\n } catch {\n args.output.stderr(\n 'error: AGENT_LOCAL_APP_INFO_JSON must map app names to OAuth/signing metadata',\n );\n return 2;\n }\n }\n let server: DevServerIface;\n try {\n server = await startDevServer({\n dir: args.dir,\n port: args.port,\n secrets,\n apps,\n output: args.output,\n });\n } catch (cause) {\n args.output.stderr(`error: ${cause instanceof Error ? cause.message : String(cause)}`);\n return 1;\n }\n let timer: ReturnType<typeof setTimeout> | null = null;\n let watcher: FSWatcher | null = null;\n try {\n watcher = watch(args.dir, { recursive: true }, (_event, file) => {\n if (file != null && isBuildOutput(file)) return;\n if (timer != null) clearTimeout(timer);\n timer = setTimeout(() => {\n args.output.stdout('change detected; recompiling');\n void server.reload();\n }, RECOMPILE_DEBOUNCE_MS);\n });\n } catch (cause) {\n args.output.stderr(\n `not watching for changes: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n await new Promise<void>((done) => {\n if (args.signal.aborted) done();\n else args.signal.addEventListener('abort', () => done(), { once: true });\n });\n if (timer != null) clearTimeout(timer);\n watcher?.close();\n await server.close();\n return 0;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -18,6 +18,13 @@ const compile = async (options) => {
18
18
  "sandboxes/environment",
19
19
  "connections",
20
20
  "channels/final",
21
+ "channels/slack",
22
+ "channels/discord",
23
+ "channels/github",
24
+ "channels/linear",
25
+ "channels/webhook",
26
+ "channels/voice",
27
+ "channels/phone",
21
28
  "channel-factories"
22
29
  ].map((path) => "@finalai/final-agent-provider/" + path);
23
30
  const providerModules = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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;",
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 'channels/slack',\n 'channels/discord',\n 'channels/github',\n 'channels/linear',\n 'channels/webhook',\n 'channels/voice',\n 'channels/phone',\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,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
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
- export { CredentialOwner, CredentialPayer, DELETE, GET, HookEvent, POST, PUT, SandboxWire, WS, always, baseTools, credentials, defineAgent, defineChannel, disableChannel, defineProviderChannel, defineDynamic, defineHarness, defineHostedConnection, defineHook, defineInstructions, defineMcpClientConnection, defineSandbox, defineSandboxProvider, defineSchedule, defineSkill, defineTool, harnessHost, never, toolResultFrom, whenInput, } from "./authoring/index.mjs";
1
+ export { CredentialOwner, CredentialPayer, DELETE, GET, HookEvent, POST, PUT, SandboxWire, WS, always, baseTools, credentials, defineAgent, defineChannel, defineRoomSurface, disableChannel, defineProviderChannel, defineDynamic, defineHarness, defineHostedConnection, defineHook, defineInstructions, defineMcpClientConnection, defineSandbox, defineSandboxProvider, defineSchedule, defineSkill, defineTool, harnessHost, never, toolResultFrom, whenInput, } from "./authoring/index.mjs";
2
2
  export type { AgentDefinitionInputIface, AgentSessionInfoIface, ApprovalPolicyIface, AuthoredChannelDefinitionIface, AuthoredHarnessCloseContextIface, AuthoredHarnessDescriptionIface, AuthoredHarnessEndpointIface, AuthoredHarnessHealthIface, AuthoredHarnessIface, AuthoredHarnessOpenArgsIface, AuthoredHarnessRefContextIface, AuthoredHarnessResumeArgsIface, BaseToolsValueIface, ConversationInfoIface, CredentialNode, CredentialPolicyIface, DefinedAuthoredHarnessIface, DefinedToolIface, DynamicDefinitionIface, DynamicResolveContextIface, DynamicSentinelIface, FinalPlatformClientIface, HarnessHostIface, HookContextIface, HookDefinitionIface, HookEventIface, HostedConnectionDefinitionIface, McpClientConnectionDefinitionIface, SandboxSelectorContextIface, ScheduleInputIface, SkillDefinitionIface, ToolContextIface, ToolDefinitionIface, } from "./authoring/index.mjs";
3
3
  export * from "./authoring/providers.mjs";
4
- export type { AgentAvatarIface, AvatarMedia, AvatarState, AgentManifestIface, ChannelDefinitionIface, ChannelPlatformIface, ChannelSocketIface, HarnessDescriptionIface, HarnessEndpointIface, HarnessIface, HarnessSessionRefIface, HostedBindingsIface, McpChannelIface, NetworkSandboxSessionIface, ResolvedAgentManifestIface, RouteDefinitionIface, SandboxMcpEndpoint, SandboxPrepareContextIface, SandboxProcessIface, SandboxProviderHandleIface, SandboxProviderIface, SandboxProviderImplementationIface, SandboxSessionIface, SandboxStartContextIface, ScreenSessionIface, } from '@finalai/agent-provider';
4
+ export type { AgentAvatarIface, AvatarMedia, AvatarState, AgentManifestIface, ChannelDefinitionIface, ChannelReceiveContextIface, ChannelEventContextIface, ConversationHandle, PersonHandle, PlaceRef, PrincipalRef, RouteDefinitionIface, RoomSurfaceDefinitionIface, RoomPlatformIface, ChannelSocketIface, HarnessDescriptionIface, HarnessEndpointIface, HarnessIface, HarnessSessionRefIface, HostedBindingsIface, McpChannelIface, NetworkSandboxSessionIface, ResolvedAgentManifestIface, SandboxMcpEndpoint, SandboxPrepareContextIface, SandboxProcessIface, SandboxProviderHandleIface, SandboxProviderIface, SandboxProviderImplementationIface, SandboxSessionIface, SandboxStartContextIface, ScreenSessionIface, } from '@finalai/agent-provider';
5
5
  export { requireHostedBinding } from '@finalai/agent-provider';
6
6
  export { validateHostedBindings } from '@finalai/agent-definition';
7
7
  export type { HostedBindingRequirementIface } from '@finalai/agent-provider';
@@ -13,6 +13,7 @@ import {
13
13
  credentials,
14
14
  defineAgent,
15
15
  defineChannel,
16
+ defineRoomSurface,
16
17
  disableChannel,
17
18
  defineProviderChannel,
18
19
  defineDynamic,
@@ -58,6 +59,7 @@ export {
58
59
  defineInstructions,
59
60
  defineMcpClientConnection,
60
61
  defineProviderChannel,
62
+ defineRoomSurface,
61
63
  defineSandbox,
62
64
  defineSandboxProvider,
63
65
  defineSchedule,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/public.ts"],
4
- "sourcesContent": ["// Agent authoring.\nexport {\n CredentialOwner,\n CredentialPayer,\n DELETE,\n GET,\n HookEvent,\n POST,\n PUT,\n SandboxWire,\n WS,\n always,\n baseTools,\n credentials,\n defineAgent,\n defineChannel,\n disableChannel,\n defineProviderChannel,\n defineDynamic,\n defineHarness,\n defineHostedConnection,\n defineHook,\n defineInstructions,\n defineMcpClientConnection,\n defineSandbox,\n defineSandboxProvider,\n defineSchedule,\n defineSkill,\n defineTool,\n harnessHost,\n never,\n toolResultFrom,\n whenInput,\n} from \"./authoring/index.mjs\";\nexport type {\n AgentDefinitionInputIface,\n AgentSessionInfoIface,\n ApprovalPolicyIface,\n AuthoredChannelDefinitionIface,\n AuthoredHarnessCloseContextIface,\n AuthoredHarnessDescriptionIface,\n AuthoredHarnessEndpointIface,\n AuthoredHarnessHealthIface,\n AuthoredHarnessIface,\n AuthoredHarnessOpenArgsIface,\n AuthoredHarnessRefContextIface,\n AuthoredHarnessResumeArgsIface,\n BaseToolsValueIface,\n ConversationInfoIface,\n CredentialNode,\n CredentialPolicyIface,\n DefinedAuthoredHarnessIface,\n DefinedToolIface,\n DynamicDefinitionIface,\n DynamicResolveContextIface,\n DynamicSentinelIface,\n FinalPlatformClientIface,\n HarnessHostIface,\n HookContextIface,\n HookDefinitionIface,\n HookEventIface,\n HostedConnectionDefinitionIface,\n McpClientConnectionDefinitionIface,\n SandboxSelectorContextIface,\n ScheduleInputIface,\n SkillDefinitionIface,\n ToolContextIface,\n ToolDefinitionIface,\n} from \"./authoring/index.mjs\";\nexport * from \"./authoring/providers.mjs\";\n\nexport type {\n AgentAvatarIface,\n AvatarMedia,\n AvatarState,\n AgentManifestIface,\n ChannelDefinitionIface,\n ChannelPlatformIface,\n ChannelSocketIface,\n HarnessDescriptionIface,\n HarnessEndpointIface,\n HarnessIface,\n HarnessSessionRefIface,\n HostedBindingsIface,\n McpChannelIface,\n NetworkSandboxSessionIface,\n ResolvedAgentManifestIface,\n RouteDefinitionIface,\n SandboxMcpEndpoint,\n SandboxPrepareContextIface,\n SandboxProcessIface,\n SandboxProviderHandleIface,\n SandboxProviderIface,\n SandboxProviderImplementationIface,\n SandboxSessionIface,\n SandboxStartContextIface,\n ScreenSessionIface,\n} from '@finalai/agent-provider';\n\nexport { requireHostedBinding } from '@finalai/agent-provider';\nexport { validateHostedBindings } from '@finalai/agent-definition';\nexport type { HostedBindingRequirementIface } from '@finalai/agent-provider';\n\nexport { defineFinalConnection } from '@finalai/final-agent-provider/connections';\nexport type {\n FinalConnectionDefinitionIface,\n FinalHostedConnectionDefinitionIface,\n} from '@finalai/final-agent-provider/connections';\n"],
5
- "mappings": "AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAoCP,cAAc;AA8Bd,SAAS,4BAA4B;AACrC,SAAS,8BAA8B;AAGvC,SAAS,6BAA6B;",
4
+ "sourcesContent": ["// Agent authoring.\nexport {\n CredentialOwner,\n CredentialPayer,\n DELETE,\n GET,\n HookEvent,\n POST,\n PUT,\n SandboxWire,\n WS,\n always,\n baseTools,\n credentials,\n defineAgent,\n defineChannel,\n defineRoomSurface,\n disableChannel,\n defineProviderChannel,\n defineDynamic,\n defineHarness,\n defineHostedConnection,\n defineHook,\n defineInstructions,\n defineMcpClientConnection,\n defineSandbox,\n defineSandboxProvider,\n defineSchedule,\n defineSkill,\n defineTool,\n harnessHost,\n never,\n toolResultFrom,\n whenInput,\n} from \"./authoring/index.mjs\";\nexport type {\n AgentDefinitionInputIface,\n AgentSessionInfoIface,\n ApprovalPolicyIface,\n AuthoredChannelDefinitionIface,\n AuthoredHarnessCloseContextIface,\n AuthoredHarnessDescriptionIface,\n AuthoredHarnessEndpointIface,\n AuthoredHarnessHealthIface,\n AuthoredHarnessIface,\n AuthoredHarnessOpenArgsIface,\n AuthoredHarnessRefContextIface,\n AuthoredHarnessResumeArgsIface,\n BaseToolsValueIface,\n ConversationInfoIface,\n CredentialNode,\n CredentialPolicyIface,\n DefinedAuthoredHarnessIface,\n DefinedToolIface,\n DynamicDefinitionIface,\n DynamicResolveContextIface,\n DynamicSentinelIface,\n FinalPlatformClientIface,\n HarnessHostIface,\n HookContextIface,\n HookDefinitionIface,\n HookEventIface,\n HostedConnectionDefinitionIface,\n McpClientConnectionDefinitionIface,\n SandboxSelectorContextIface,\n ScheduleInputIface,\n SkillDefinitionIface,\n ToolContextIface,\n ToolDefinitionIface,\n} from \"./authoring/index.mjs\";\nexport * from \"./authoring/providers.mjs\";\n\nexport type {\n AgentAvatarIface,\n AvatarMedia,\n AvatarState,\n AgentManifestIface,\n ChannelDefinitionIface,\n ChannelReceiveContextIface,\n ChannelEventContextIface,\n ConversationHandle,\n PersonHandle,\n PlaceRef,\n PrincipalRef,\n RouteDefinitionIface,\n RoomSurfaceDefinitionIface,\n RoomPlatformIface,\n ChannelSocketIface,\n HarnessDescriptionIface,\n HarnessEndpointIface,\n HarnessIface,\n HarnessSessionRefIface,\n HostedBindingsIface,\n McpChannelIface,\n NetworkSandboxSessionIface,\n ResolvedAgentManifestIface,\n SandboxMcpEndpoint,\n SandboxPrepareContextIface,\n SandboxProcessIface,\n SandboxProviderHandleIface,\n SandboxProviderIface,\n SandboxProviderImplementationIface,\n SandboxSessionIface,\n SandboxStartContextIface,\n ScreenSessionIface,\n} from '@finalai/agent-provider';\n\nexport { requireHostedBinding } from '@finalai/agent-provider';\nexport { validateHostedBindings } from '@finalai/agent-definition';\nexport type { HostedBindingRequirementIface } from '@finalai/agent-provider';\n\nexport { defineFinalConnection } from '@finalai/final-agent-provider/connections';\nexport type {\n FinalConnectionDefinitionIface,\n FinalHostedConnectionDefinitionIface,\n} from '@finalai/final-agent-provider/connections';\n"],
5
+ "mappings": "AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAoCP,cAAc;AAqCd,SAAS,4BAA4B;AACrC,SAAS,8BAA8B;AAGvC,SAAS,6BAA6B;",
6
6
  "names": []
7
7
  }
@@ -1,38 +1,2 @@
1
- import { defineChannel, POST } from '@finalai/agents/channels';
2
- import * as z from 'zod';
3
- import { verifyGithubSignature } from './github-signature';
4
-
5
- const actionSchema = z.object({ action: z.string() });
6
- const releaseEventSchema = actionSchema.extend({ release: z.object({ tag_name: z.string() }) });
7
-
8
- export default defineChannel({
9
- routes: [
10
- POST('/webhook', async ({ request, secrets, receive }) => {
11
- const body = await request.text();
12
- if (
13
- !(await verifyGithubSignature(request, body, await secrets.get('github-webhook-secret')))
14
- ) {
15
- return new Response(null, { status: 401 });
16
- }
17
- let raw: unknown;
18
- try {
19
- raw = JSON.parse(body);
20
- } catch {
21
- return new Response(null, { status: 400 });
22
- }
23
- const action = actionSchema.safeParse(raw);
24
- if (!action.success) return new Response(null, { status: 400 });
25
- if (action.data.action !== 'published') return new Response(null, { status: 204 });
26
- const parsed = releaseEventSchema.safeParse(raw);
27
- if (!parsed.success) return new Response(null, { status: 400 });
28
- await receive({
29
- target: { kind: 'bound-conversation' },
30
- content: [
31
- { type: 'text', text: `GitHub release published: ${parsed.data.release.tag_name}` },
32
- ],
33
- });
34
- return new Response(null, { status: 202 });
35
- }),
36
- ],
37
- turnPolicy: 'steer',
38
- });
1
+ import { webhookChannel } from '@finalai/final-agent-provider/channels/webhook';
2
+ export default webhookChannel({ secret: 'github-webhook-secret' });
@@ -15,7 +15,7 @@ export default defineHook({
15
15
  console.warn('release notes missing', { tag: event.data.rawInput['tag'] });
16
16
  },
17
17
  async '*'(event, ctx) {
18
- await fetch('https://audit.internal/events', {
18
+ await fetch('https://audit.example.com/events', {
19
19
  method: 'POST',
20
20
  body: JSON.stringify({ id: event.meta.id, session: ctx.session.id, type: event.type }),
21
21
  });
@@ -11,7 +11,7 @@ export default defineDynamic({
11
11
  preview: 'Release calendar: 2.4.1 on 2026-10-10. On-call: @mina.',
12
12
  events: {
13
13
  'session.started': async (_event, ctx) => {
14
- const url = new URL('https://ops.internal/calendar');
14
+ const url = new URL('https://ops.example.com/calendar');
15
15
  url.searchParams.set('org', ctx.session.organizationId);
16
16
  const res = await fetch(url);
17
17
  const text = await res.text();