@kelloggt/dsh-program-agents 0.0.0-stage → 0.1.1

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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -2
  3. package/cordis.patch.yml +5 -0
  4. package/dist/app/agents.d.ts +50 -0
  5. package/dist/app/agents.js +70 -0
  6. package/dist/app/agents.js.map +1 -0
  7. package/dist/app/conversations.d.ts +8 -0
  8. package/dist/app/conversations.js +26 -0
  9. package/dist/app/conversations.js.map +1 -0
  10. package/dist/app/endpoints.d.ts +36 -0
  11. package/dist/app/endpoints.js +162 -0
  12. package/dist/app/endpoints.js.map +1 -0
  13. package/dist/app/inbox.d.ts +61 -0
  14. package/dist/app/inbox.js +253 -0
  15. package/dist/app/inbox.js.map +1 -0
  16. package/dist/app/index.d.ts +70 -0
  17. package/dist/app/index.js +147 -0
  18. package/dist/app/index.js.map +1 -0
  19. package/dist/app/mailbox.d.ts +63 -0
  20. package/dist/app/mailbox.js +173 -0
  21. package/dist/app/mailbox.js.map +1 -0
  22. package/dist/app/models.d.ts +32 -0
  23. package/dist/app/models.js +13 -0
  24. package/dist/app/models.js.map +1 -0
  25. package/dist/app/server.d.ts +36 -0
  26. package/dist/app/server.js +233 -0
  27. package/dist/app/server.js.map +1 -0
  28. package/dist/app/stream-server.d.ts +9 -0
  29. package/dist/app/stream-server.js +77 -0
  30. package/dist/app/stream-server.js.map +1 -0
  31. package/dist/app/stream.d.ts +4 -0
  32. package/dist/app/stream.js +93 -0
  33. package/dist/app/stream.js.map +1 -0
  34. package/dist/app/tools.d.ts +16 -0
  35. package/dist/app/tools.js +24 -0
  36. package/dist/app/tools.js.map +1 -0
  37. package/dist/client/controller.d.ts +21 -0
  38. package/dist/client/controller.js +140 -0
  39. package/dist/client/controller.js.map +1 -0
  40. package/dist/client/index.d.ts +22 -0
  41. package/dist/client/index.js +14 -0
  42. package/dist/client/index.js.map +1 -0
  43. package/dist/client/model.d.ts +66 -0
  44. package/dist/client/model.js +147 -0
  45. package/dist/client/model.js.map +1 -0
  46. package/dist/client/models.d.ts +11 -0
  47. package/dist/client/models.js +27 -0
  48. package/dist/client/models.js.map +1 -0
  49. package/dist/client/transport.d.ts +64 -0
  50. package/dist/client/transport.js +141 -0
  51. package/dist/client/transport.js.map +1 -0
  52. package/dist/client/view.d.ts +19 -0
  53. package/dist/client/view.js +69 -0
  54. package/dist/client/view.js.map +1 -0
  55. package/dist/client.js +673 -0
  56. package/dist/conversations.d.ts +92 -0
  57. package/dist/conversations.js +6 -0
  58. package/dist/conversations.js.map +1 -0
  59. package/dist/endpoints.d.ts +48 -0
  60. package/dist/endpoints.js +43 -0
  61. package/dist/endpoints.js.map +1 -0
  62. package/dist/examples/dashboard.js +42 -0
  63. package/dist/examples/dynamic-server.js +27 -0
  64. package/dist/examples/inbox-worker.js +22 -0
  65. package/dist/examples/model-slots.js +19 -0
  66. package/dist/examples/standalone-supervisor.js +20 -0
  67. package/dist/host/adapter.d.ts +195 -0
  68. package/dist/host/adapter.js +630 -0
  69. package/dist/host/adapter.js.map +1 -0
  70. package/dist/host/agents.d.ts +35 -0
  71. package/dist/host/agents.js +222 -0
  72. package/dist/host/agents.js.map +1 -0
  73. package/dist/host/audit.d.ts +14 -0
  74. package/dist/host/audit.js +39 -0
  75. package/dist/host/audit.js.map +1 -0
  76. package/dist/host/catalog.d.ts +53 -0
  77. package/dist/host/catalog.js +116 -0
  78. package/dist/host/catalog.js.map +1 -0
  79. package/dist/host/contracts.d.ts +38 -0
  80. package/dist/host/contracts.js +2 -0
  81. package/dist/host/contracts.js.map +1 -0
  82. package/dist/host/conversations.d.ts +41 -0
  83. package/dist/host/conversations.js +324 -0
  84. package/dist/host/conversations.js.map +1 -0
  85. package/dist/host/events.d.ts +12 -0
  86. package/dist/host/events.js +106 -0
  87. package/dist/host/events.js.map +1 -0
  88. package/dist/host/http.d.ts +14 -0
  89. package/dist/host/http.js +30 -0
  90. package/dist/host/http.js.map +1 -0
  91. package/dist/host/index.d.ts +23 -0
  92. package/dist/host/index.js +86 -0
  93. package/dist/host/index.js.map +1 -0
  94. package/dist/host/installed-v10.js +27181 -0
  95. package/dist/host/installed-v11.js +27181 -0
  96. package/dist/host/installed-v12.js +27181 -0
  97. package/dist/host/installed-v13.js +27181 -0
  98. package/dist/host/installed-v2.js +27181 -0
  99. package/dist/host/installed-v3.js +27181 -0
  100. package/dist/host/installed-v4.js +27181 -0
  101. package/dist/host/installed-v5.js +27181 -0
  102. package/dist/host/installed-v6.js +27181 -0
  103. package/dist/host/installed-v7.js +27181 -0
  104. package/dist/host/installed-v8.js +27181 -0
  105. package/dist/host/installed-v9.js +27181 -0
  106. package/dist/host/mcp.d.ts +11 -0
  107. package/dist/host/mcp.js +42 -0
  108. package/dist/host/mcp.js.map +1 -0
  109. package/dist/host/models.d.ts +37 -0
  110. package/dist/host/models.js +141 -0
  111. package/dist/host/models.js.map +1 -0
  112. package/dist/host/operations.d.ts +22 -0
  113. package/dist/host/operations.js +72 -0
  114. package/dist/host/operations.js.map +1 -0
  115. package/dist/host/plugin.js +27181 -0
  116. package/dist/host/policies.d.ts +36 -0
  117. package/dist/host/policies.js +73 -0
  118. package/dist/host/policies.js.map +1 -0
  119. package/dist/host/requests.d.ts +57 -0
  120. package/dist/host/requests.js +353 -0
  121. package/dist/host/requests.js.map +1 -0
  122. package/dist/host/skills.d.ts +2 -0
  123. package/dist/host/skills.js +45 -0
  124. package/dist/host/skills.js.map +1 -0
  125. package/dist/host/tool-client.d.ts +19 -0
  126. package/dist/host/tool-client.js +62 -0
  127. package/dist/host/tool-client.js.map +1 -0
  128. package/dist/host/validation.d.ts +5 -0
  129. package/dist/host/validation.js +42 -0
  130. package/dist/host/validation.js.map +1 -0
  131. package/dist/mcp.d.ts +7 -0
  132. package/dist/mcp.js +2 -0
  133. package/dist/mcp.js.map +1 -0
  134. package/dist/models.d.ts +34 -0
  135. package/dist/models.js +53 -0
  136. package/dist/models.js.map +1 -0
  137. package/dist/monitoring/error-buffer.d.ts +89 -0
  138. package/dist/monitoring/error-buffer.js +355 -0
  139. package/dist/monitoring/error-buffer.js.map +1 -0
  140. package/dist/monitoring/fatal.d.ts +6 -0
  141. package/dist/monitoring/fatal.js +32 -0
  142. package/dist/monitoring/fatal.js.map +1 -0
  143. package/dist/monitoring/index.d.ts +7 -0
  144. package/dist/monitoring/index.js +8 -0
  145. package/dist/monitoring/index.js.map +1 -0
  146. package/dist/monitoring/logger.d.ts +45 -0
  147. package/dist/monitoring/logger.js +174 -0
  148. package/dist/monitoring/logger.js.map +1 -0
  149. package/dist/monitoring/schemas.d.ts +34 -0
  150. package/dist/monitoring/schemas.js +132 -0
  151. package/dist/monitoring/schemas.js.map +1 -0
  152. package/dist/monitoring/standard.d.ts +51 -0
  153. package/dist/monitoring/standard.js +140 -0
  154. package/dist/monitoring/standard.js.map +1 -0
  155. package/dist/monitoring/tailer.d.ts +41 -0
  156. package/dist/monitoring/tailer.js +210 -0
  157. package/dist/monitoring/tailer.js.map +1 -0
  158. package/dist/requests.d.ts +92 -0
  159. package/dist/requests.js +120 -0
  160. package/dist/requests.js.map +1 -0
  161. package/dist/runtime/bootstrap.d.ts +1 -0
  162. package/dist/runtime/bootstrap.js +25 -0
  163. package/dist/runtime/bootstrap.js.map +1 -0
  164. package/dist/runtime/definitions.d.ts +7 -0
  165. package/dist/runtime/definitions.js +138 -0
  166. package/dist/runtime/definitions.js.map +1 -0
  167. package/dist/runtime/index.d.ts +4 -0
  168. package/dist/runtime/index.js +4 -0
  169. package/dist/runtime/index.js.map +1 -0
  170. package/dist/runtime/log-file.d.ts +24 -0
  171. package/dist/runtime/log-file.js +124 -0
  172. package/dist/runtime/log-file.js.map +1 -0
  173. package/dist/runtime/protocol.d.ts +60 -0
  174. package/dist/runtime/protocol.js +155 -0
  175. package/dist/runtime/protocol.js.map +1 -0
  176. package/dist/runtime/registry.d.ts +8 -0
  177. package/dist/runtime/registry.js +38 -0
  178. package/dist/runtime/registry.js.map +1 -0
  179. package/dist/runtime/supervisor.d.ts +74 -0
  180. package/dist/runtime/supervisor.js +881 -0
  181. package/dist/runtime/supervisor.js.map +1 -0
  182. package/dist/sdk/connection.d.ts +33 -0
  183. package/dist/sdk/connection.js +265 -0
  184. package/dist/sdk/connection.js.map +1 -0
  185. package/dist/sdk/index.d.ts +8 -0
  186. package/dist/sdk/index.js +2 -0
  187. package/dist/sdk/index.js.map +1 -0
  188. package/dist/supervision.d.ts +22 -0
  189. package/dist/supervision.js +32 -0
  190. package/dist/supervision.js.map +1 -0
  191. package/dist/types.d.ts +170 -0
  192. package/dist/types.js +2 -0
  193. package/dist/types.js.map +1 -0
  194. package/docs/installation.md +37 -0
  195. package/docs/log-format.md +102 -0
  196. package/docs/publishing.md +45 -0
  197. package/docs/supervision.md +73 -0
  198. package/examples/dashboard.ts +31 -0
  199. package/examples/dsh-web-local.patch.yml +15 -0
  200. package/examples/dynamic-server.ts +13 -0
  201. package/examples/inbox-worker.ts +17 -0
  202. package/examples/model-slots.ts +12 -0
  203. package/examples/standalone-supervisor.ts +14 -0
  204. package/examples/watch-server.ts +12 -0
  205. package/package.json +134 -3
  206. package/schemas/dsh.http.request.v1.schema.json +14 -0
  207. package/schemas/dsh.program.error-batch.v1.schema.json +24 -0
  208. package/schemas/dsh.program.error.v1.schema.json +8 -0
  209. package/schemas/standard-log-record.v1.schema.json +26 -0
  210. package/skills/program-agents/SKILL.md +124 -0
  211. package/skills/program-agents/chat-sidebar.md +23 -0
  212. package/skills/program-agents/endpoints.md +92 -0
  213. package/skills/program-agents/inboxes.md +120 -0
  214. package/skills/program-agents/log-format.md +102 -0
  215. package/skills/program-agents/models.md +59 -0
  216. package/skills/program-agents/references/chat-sidebar/AgentSidebar.tsx +181 -0
  217. package/skills/program-agents/references/chat-sidebar/README.md +181 -0
  218. package/skills/program-agents/references/chat-sidebar/agent-sidebar.css +37 -0
  219. package/skills/program-agents/references/chat-sidebar/backend.ts +184 -0
  220. package/skills/program-agents/references/chat-sidebar/protocol.ts +214 -0
  221. package/skills/program-agents/schemas/dsh.http.request.v1.schema.json +14 -0
  222. package/skills/program-agents/schemas/dsh.program.error-batch.v1.schema.json +24 -0
  223. package/skills/program-agents/schemas/dsh.program.error.v1.schema.json +8 -0
  224. package/skills/program-agents/schemas/standard-log-record.v1.schema.json +26 -0
  225. package/skills/program-agents/ui-patterns.md +39 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tim Kellogg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,91 @@
1
- # Temporary Holding Version
1
+ # DSH Program Agents
2
+
3
+ You know how subagents can send messages to each other, launch new subagents, call LLMs, use tools, etc? A lot of agents write non-trivial amounts of code just to operate normally. _What if an "agent" was just code?_
4
+
5
+ _**Program agents**_ — no agent loop, just regular software that a supervising agent can edit & manage.
6
+
7
+ This repo includes
8
+ * A typescript SDK for [DSH (DeepSeek Harness)](https://github.com/deepseek-ai/deepseek-harness) that wraps tool calling, LLM calling, inter-agent messaging, etc.
9
+ * A process manager that keeps the program agent running, or not, whatever you need
10
+ * Logging/monitoring so that errors get funneled to the supervising agent
11
+ * Named models for configurable software so you can upgrade models easily
12
+ * A skill to teach your agent how to write program agents
13
+
14
+ ## Installation
15
+
16
+ You'll need [Node.js](https://nodejs.org/) **22.18 or newer**. This plugin currently targets **DSH 0.2.1-rc.2**; use that version for the setup below.
17
+
18
+ ### 1. Install DSH
19
+
20
+ Install the [DSH CLI](https://github.com/deepseek-ai/deepseek-harness) and pnpm:
21
+
22
+ ```sh
23
+ npm install -g @deepseek-ai/dsh@0.2.1-rc.2 pnpm@10
24
+ dsh web
25
+ ```
26
+
27
+ DSH opens its web UI at `http://127.0.0.1:3080` and creates your web profile. Stop it with **Ctrl+C** while you install the plugins below.
28
+
29
+ ### 2. Install Program Agents
30
+
31
+ Install the npm package into DSH's web profile:
32
+
33
+ ```sh
34
+ dsh plugin --profile web add @kelloggt/dsh-program-agents
35
+ ```
36
+
37
+ DSH enables the plugin and discovers its bundled **program-agents** skill automatically in version **0.1.1 and later**. Package upgrades update the skill too.
38
+
39
+ If you previously copied the skill into `~/.dsh/skills/program-agents`, that copy takes precedence. Remove an old, unmodified copy to use the bundled version; keep it if you maintain your own instructions.
40
+
41
+ ### 3. Connect Codex or Claude
42
+
43
+ To use your ChatGPT or Claude subscription, install [dsh-plugin-subscriptions](https://github.com/V1ki/dsh-plugin-subscriptions):
44
+
45
+ ```sh
46
+ dsh plugin --profile web add dsh-plugin-subscriptions
47
+ dsh web
48
+ ```
49
+
50
+ In DSH, open **Settings → Subscriptions** and click **Connect** for the provider you want:
51
+
52
+ - **ChatGPT (Codex):** sign in with your ChatGPT account in the browser.
53
+ - **Claude:** imports your existing Claude Code login when available. Otherwise, follow the browser authorization flow; the Claude Code CLI is optional.
54
+
55
+ These providers use your subscription login, so no API key is needed. Open the session's model picker (`/model`) and select a model under **ChatGPT (Codex)** or **Claude (Subscription)**.
56
+
57
+ If you use another model provider, skip the subscriptions plugin and run `dsh web` after step 2. In a new chat, ask DSH to use the **program-agents** skill to build and start a program. The **Program agents** panel above the composer shows its status and Start/Stop/Restart controls.
58
+
59
+ ## Why not just regular software?
60
+ * _Error handling_ — software that discovers problems and dynamically adapts
61
+ * _Slowly changing software_ — e.g. in data engineering you'll run into new data bugs or learn new things about the data in production. Program agents merely evolve to handle new situations
62
+ * _World-integrated agents_ — a collection of loops that poll web services like Github or Salesforce for events and messages and forward them onto a real agent
63
+ * _Heavily AI-integrated software_ — Regular software with agents and chatbots wired deeply throughout
64
+
65
+ ## Default workflow
66
+
67
+ 1. Build an app using a foreground **watch/reload** command.
68
+ 2. Register its name, description, argv command, URLs and optional log path with `program_register`.
69
+ 3. Start using `program_start` or the composer's **Start** button. The UI dispatches through the exact live parent's public tool pipeline; it does not create an unrelated shell/Agent.
70
+ 4. Edit source; let the watcher reload rather than repeatedly restarting manually. Check application readiness using its actual health/API URL and logs.
71
+
72
+ ## Development commands
73
+
74
+ Run `pnpm install --frozen-lockfile` after cloning, then use these scripts from the repository root:
75
+
76
+ | Command | Purpose |
77
+ | --- | --- |
78
+ | `pnpm build` | Build the host, browser client, SDK, and examples. |
79
+ | `pnpm typecheck` | Check the source TypeScript. |
80
+ | `pnpm typecheck:references` | Check the copyable application references. |
81
+ | `pnpm test` | Run the test suite. |
82
+ | `pnpm check` | Build, check references, and run tests. |
83
+ | `pnpm example` | Run the standalone supervisor example. |
84
+ | `pnpm release:pack` | Run all checks and create the release archive. |
85
+ | `pnpm release:inspect` | List the files in the current version's archive. |
86
+ | `pnpm release:publish:dry-run` | Preview publishing the archive. |
87
+ | `pnpm release:login` | Sign in to npm. |
88
+ | `pnpm release:publish` | Publish the existing archive publicly to npm. |
89
+
90
+ See [Publishing to npm](docs/publishing.md) for the release workflow.
2
91
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
@@ -0,0 +1,5 @@
1
+ # Installing this bundle enables the host plugin. DSH discovers the web client
2
+ # through the dsh.client declaration in package.json.
3
+ - insert:
4
+ - id: program-agents
5
+ name: '@kelloggt/dsh-program-agents'
@@ -0,0 +1,50 @@
1
+ import type { JsonValue } from '../types.js';
2
+ import { type AgentTarget, type ResponseSchema, type RequestRecord } from '../requests.js';
3
+ import { ProgramError } from '../runtime/protocol.js';
4
+ import type { AgentInfo, CallOptions, SendOptions } from './index.js';
5
+ export type { AgentTarget, ResponseSchema, JSONSchema, RequestStatus, ResponseReceipt } from '../requests.js';
6
+ export interface AgentRequestView {
7
+ requestId: string;
8
+ status: RequestRecord['status'];
9
+ agentId?: string;
10
+ createdAt: string;
11
+ deadline: string;
12
+ response?: JsonValue;
13
+ error?: string;
14
+ }
15
+ export interface AskOptions extends CallOptions {
16
+ requestId?: string;
17
+ responseSchema?: ResponseSchema;
18
+ instructions?: string;
19
+ }
20
+ /** Runtime schema plus identity parser for statically typed ask results. A TS
21
+ * interface alone disappears at runtime and cannot validate an Agent reply. */
22
+ export interface AgentResponseType<T extends JsonValue> {
23
+ readonly schema: ResponseSchema;
24
+ parse(value: JsonValue): T;
25
+ }
26
+ export declare function responseType<T extends JsonValue>(schema: ResponseSchema): AgentResponseType<T>;
27
+ export declare const responseTypes: {
28
+ string: () => AgentResponseType<string>;
29
+ };
30
+ export declare class AgentRequestError extends ProgramError {
31
+ readonly requestId: string;
32
+ readonly status: RequestRecord['status'];
33
+ constructor(code: string, message: string, requestId: string, status: RequestRecord['status']);
34
+ }
35
+ export type AgentBridgeCall = <T = JsonValue>(method: string, input?: JsonValue, options?: CallOptions) => Promise<T>;
36
+ export interface ProgramAgents {
37
+ list(options?: CallOptions): Promise<AgentInfo[]>;
38
+ get(id: string, options?: CallOptions): Promise<AgentInfo | null>;
39
+ send(target: AgentTarget, body: JsonValue, options?: SendOptions): Promise<JsonValue>;
40
+ ask(target: AgentTarget, body: JsonValue, options?: AskOptions & {
41
+ responseSchema?: undefined;
42
+ }): Promise<string>;
43
+ ask<T extends JsonValue = JsonValue>(target: AgentTarget, body: JsonValue, options: AskOptions & {
44
+ responseSchema: ResponseSchema;
45
+ }): Promise<T>;
46
+ ask<T extends JsonValue>(target: AgentTarget, body: JsonValue, responseType: AgentResponseType<T>, options?: AskOptions): Promise<T>;
47
+ request(requestId: string, options?: CallOptions): Promise<AgentRequestView | null>;
48
+ cancel(requestId: string, options?: CallOptions): Promise<AgentRequestView>;
49
+ }
50
+ export declare function createProgramAgents(call: AgentBridgeCall): ProgramAgents;
@@ -0,0 +1,70 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { createResponseValidator } from '../requests.js';
3
+ import { ProgramError } from '../runtime/protocol.js';
4
+ export function responseType(schema) { const validate = createResponseValidator(schema); return { schema, parse(value) { validate(value); return value; } }; }
5
+ export const responseTypes = { string: () => responseType({ type: 'string' }) };
6
+ export class AgentRequestError extends ProgramError {
7
+ requestId;
8
+ status;
9
+ constructor(code, message, requestId, status) {
10
+ super(code, message);
11
+ this.requestId = requestId;
12
+ this.status = status;
13
+ }
14
+ }
15
+ export function createProgramAgents(call) {
16
+ const request = (requestId, options) => call('agents.request', { requestId }, options);
17
+ const cancel = (requestId, options) => call('agents.cancel', { requestId }, options);
18
+ const ask = async (target, body, options = {}) => {
19
+ const timeout = options.timeoutMs ?? 120000;
20
+ if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 3600000)
21
+ throw new ProgramError('INVALID_INPUT', 'Agent ask timeout must be 1..3600000ms');
22
+ options.signal?.throwIfAborted();
23
+ const key = options.requestId ?? randomUUID();
24
+ // Compile before sending anything: invalid schemas cannot spend model tokens.
25
+ const validate = createResponseValidator(options.responseSchema);
26
+ let view;
27
+ const controller = new AbortController(), timer = setTimeout(() => controller.abort(new ProgramError('TIMEOUT', 'Agent response deadline exceeded')), timeout);
28
+ const abort = () => controller.abort(options.signal?.reason ?? new ProgramError('CANCELLED', 'Agent ask cancelled'));
29
+ options.signal?.addEventListener('abort', abort, { once: true });
30
+ try {
31
+ view = await call('agents.ask', { target: target, body, requestId: key, timeoutMs: timeout, ...options.responseSchema === undefined ? {} : { responseSchema: options.responseSchema }, ...options.instructions === undefined ? {} : { prompt: options.instructions } }, { signal: controller.signal, timeoutMs: Math.min(timeout, 120000) });
32
+ while (view.status === 'pending')
33
+ view = await call('agents.wait', { requestId: view.requestId, waitMs: Math.min(25000, Math.max(0, Date.parse(view.deadline) - Date.now())) }, { signal: controller.signal, timeoutMs: 30000 });
34
+ if (view.status === 'answered') {
35
+ validate(view.response);
36
+ return view.response;
37
+ }
38
+ throw new AgentRequestError(view.status === 'dispatch-unknown' ? 'DISPATCH_UNKNOWN' : view.status === 'expired' ? 'TIMEOUT' : view.status === 'cancelled' ? 'CANCELLED' : 'AGENT_REQUEST_FAILED', view.error ?? 'Agent request ' + view.status, view.requestId, view.status);
39
+ }
40
+ catch (error) {
41
+ // Cancellation only settles this response contract, never pretends the Agent's
42
+ // reasoning/external effects were undone. No message/delegation retries.
43
+ if (controller.signal.aborted) {
44
+ await cancel(view?.requestId ?? key, { timeoutMs: 5000 }).catch(() => { });
45
+ throw new AgentRequestError(options.signal?.aborted ? 'CANCELLED' : 'TIMEOUT', 'Agent ask interrupted; inspect the durable request before repeating work', view?.requestId ?? key, view?.status ?? 'pending');
46
+ }
47
+ if (error instanceof AgentRequestError)
48
+ throw error;
49
+ if (view?.status === 'answered' && error instanceof ProgramError && error.code === 'INVALID_RESPONSE')
50
+ throw error;
51
+ if (error instanceof ProgramError && !['TIMEOUT', 'CANCELLED', 'INVALID_RESPONSE', 'CALL_FAILED'].includes(error.code))
52
+ throw error;
53
+ throw new AgentRequestError('DISPATCH_UNKNOWN', 'Request transport failed; inspect using the request key before repeating work', view?.requestId ?? key, view?.status ?? 'dispatch-unknown');
54
+ }
55
+ finally {
56
+ clearTimeout(timer);
57
+ options.signal?.removeEventListener('abort', abort);
58
+ }
59
+ };
60
+ return {
61
+ list: options => call('agents.list', null, options), get: (id, options) => call('agents.get', { id }, options),
62
+ send: (target, body, options = {}) => call('agents.send', { ...typeof target === 'string' ? { id: target } : { target: target }, body, ...options.correlationId === undefined ? {} : { correlationId: options.correlationId } }, options),
63
+ ask: ((target, body, typeOrOptions = {}, options = {}) => {
64
+ if ('schema' in typeOrOptions && 'parse' in typeOrOptions)
65
+ return ask(target, body, { ...options, responseSchema: typeOrOptions.schema }).then(value => typeOrOptions.parse(value));
66
+ return ask(target, body, typeOrOptions);
67
+ }), request, cancel,
68
+ };
69
+ }
70
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/app/agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { JsonValue } from '../types.js';
2
+ import type { CallOptions } from './index.js';
3
+ import type { ProgramConversations } from '../conversations.js';
4
+ export type * from '../conversations.js';
5
+ export type ConversationBridgeCall = <T = JsonValue>(method: string, input?: JsonValue, options?: CallOptions) => Promise<T>;
6
+ export type ConversationBridgeStream = (method: string, input?: JsonValue, options?: CallOptions) => AsyncIterable<JsonValue>;
7
+ /** App-side handles contain no credentials, Agent objects, model calls, or tool loop. */
8
+ export declare function createProgramConversations(call: ConversationBridgeCall, stream: ConversationBridgeStream): ProgramConversations;
@@ -0,0 +1,26 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { ProgramError } from '../runtime/protocol.js';
3
+ /** App-side handles contain no credentials, Agent objects, model calls, or tool loop. */
4
+ export function createProgramConversations(call, stream) {
5
+ const sendInput = (id, message, options = {}) => ({
6
+ id, message: message, requestId: options.requestId ?? randomUUID(), ...(options.mode === undefined ? {} : { mode: options.mode }),
7
+ });
8
+ const handle = (info) => Object.freeze({
9
+ ...info,
10
+ history: (options, callOptions) => call('conversations.history', { id: info.id, ...options }, callOptions),
11
+ events: (options = {}) => stream('conversations.events', { id: info.id, ...(options.maxMessages === undefined ? {} : { maxMessages: options.maxMessages }) }, { signal: options.signal }),
12
+ send: (message, options = {}) => call('conversations.send', sendInput(info.id, message, options), { signal: options.signal }),
13
+ ask: (message, options = {}) => {
14
+ if ('mode' in options && options.mode !== 'queue')
15
+ throw new ProgramError('INVALID_INPUT', 'Conversation ask requires a queued, distinct turn; use send for steering');
16
+ return stream('conversations.ask', sendInput(info.id, message, { requestId: options.requestId, signal: options.signal }), { signal: options.signal });
17
+ },
18
+ interrupt: options => call('conversations.interrupt', { id: info.id }, options),
19
+ });
20
+ return {
21
+ open: async (options, callOptions) => handle(await call('conversations.open', options, callOptions)),
22
+ get: async (id, options) => { const info = await call('conversations.get', { id }, options); return info ? handle(info) : null; },
23
+ list: options => call('conversations.list', {}, options),
24
+ };
25
+ }
26
+ //# sourceMappingURL=conversations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../src/app/conversations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { Server } from 'node:net';
2
+ import type { ProgramEndpointBinding } from '../endpoints.js';
3
+ import type { JsonValue } from '../types.js';
4
+ import type { CallOptions } from './index.js';
5
+ export type { ProgramEndpointBinding } from '../endpoints.js';
6
+ export interface PublishEndpointOptions {
7
+ port: number;
8
+ }
9
+ export interface UnpublishEndpointOptions {
10
+ port?: number;
11
+ }
12
+ export interface ListeningProgramEndpoint {
13
+ port: number;
14
+ /** Authoritative bind host, not a browser-facing hostname. */
15
+ host: string;
16
+ /** Local verification URL; wildcard binds use their loopback equivalent. */
17
+ localUrl: string;
18
+ /** Close this listener and await its conditional unpublication. Idempotent. */
19
+ close(): Promise<void>;
20
+ }
21
+ export interface ProgramEndpoints {
22
+ list(options?: CallOptions): Promise<ProgramEndpointBinding[]>;
23
+ publish(id: string, address: PublishEndpointOptions, options?: CallOptions): Promise<ProgramEndpointBinding>;
24
+ unpublish(id: string, address?: UnpublishEndpointOptions, options?: CallOptions): Promise<ProgramEndpointBinding>;
25
+ /** Bind using current host configuration, then advertise the actual OS port. */
26
+ listen(id: string, server: Server, options?: CallOptions): Promise<ListeningProgramEndpoint>;
27
+ }
28
+ export type EndpointBridgeCall = <T = JsonValue>(method: string, input?: JsonValue, options?: CallOptions) => Promise<T>;
29
+ /** Typed endpoint bridge helpers. Calls are never retried and use existing call cancellation. */
30
+ export declare function createProgramEndpoints(call: EndpointBridgeCall): ProgramEndpoints;
31
+ /**
32
+ * Bind a fresh Node net/http/https server using authoritative bridge configuration.
33
+ * Existing published ports and the app's environment do not choose the bind address.
34
+ * Frameworks managing their own listeners can instead use list/publish/unpublish.
35
+ */
36
+ export declare function listenProgramEndpoint(endpoints: Pick<ProgramEndpoints, 'list' | 'publish' | 'unpublish'>, id: string, server: Server, options?: CallOptions): Promise<ListeningProgramEndpoint>;
@@ -0,0 +1,162 @@
1
+ import { endpointName } from '../endpoints.js';
2
+ import { ProgramError } from '../runtime/protocol.js';
3
+ const managedServers = new WeakSet();
4
+ const cancelled = () => new ProgramError('CANCELLED', 'Endpoint listen was cancelled');
5
+ const unavailable = () => new ProgramError('UNAVAILABLE', 'Endpoint server closed during setup');
6
+ const unbracket = (host) => host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
7
+ /** Typed endpoint bridge helpers. Calls are never retried and use existing call cancellation. */
8
+ export function createProgramEndpoints(call) {
9
+ const endpoints = {
10
+ list: (options) => call('endpoints.list', null, options),
11
+ publish: (id, { port }, options) => call('endpoints.publish', { id, port }, options),
12
+ unpublish: (id, { port } = {}, options) => call('endpoints.unpublish', { id, ...(port === undefined ? {} : { port }) }, options),
13
+ listen: (id, server, options) => listenProgramEndpoint(endpoints, id, server, options),
14
+ };
15
+ return endpoints;
16
+ }
17
+ /**
18
+ * Bind a fresh Node net/http/https server using authoritative bridge configuration.
19
+ * Existing published ports and the app's environment do not choose the bind address.
20
+ * Frameworks managing their own listeners can instead use list/publish/unpublish.
21
+ */
22
+ export async function listenProgramEndpoint(endpoints, id, server, options = {}) {
23
+ if (!endpointName(id))
24
+ throw new ProgramError('INVALID_INPUT', 'Invalid endpoint id');
25
+ if (server.listening || managedServers.has(server))
26
+ throw new ProgramError('BUSY', 'Endpoint helper requires an unbound, unmanaged server');
27
+ managedServers.add(server);
28
+ let attemptedBind = false;
29
+ let closed = false;
30
+ let setupComplete = false;
31
+ let setupFailed = false;
32
+ let setupError;
33
+ let port;
34
+ let publication;
35
+ let unpublication;
36
+ let closing;
37
+ let rejectSetup;
38
+ let resolveListening;
39
+ const interrupted = new Promise((_resolve, reject) => { rejectSetup = reject; });
40
+ // An error can arrive between awaited setup stages, before the next race attaches.
41
+ void interrupted.catch(() => { });
42
+ const listening = new Promise((resolve) => { resolveListening = resolve; });
43
+ const onListening = () => resolveListening();
44
+ const failSetup = (error) => {
45
+ if (!setupFailed) {
46
+ setupFailed = true;
47
+ setupError = error;
48
+ }
49
+ rejectSetup(error);
50
+ };
51
+ const onError = (error) => failSetup(error);
52
+ const onAbort = () => failSetup(cancelled());
53
+ const unpublish = () => {
54
+ if (!publication || port === undefined)
55
+ return Promise.resolve();
56
+ // A close during publication must unpublish AFTER that call settles, not before it.
57
+ return unpublication ??= (async () => {
58
+ await publication.catch(() => { });
59
+ await endpoints.unpublish(id, { port });
60
+ })();
61
+ };
62
+ const onClose = () => {
63
+ closed = true;
64
+ if (!setupComplete)
65
+ failSetup(unavailable());
66
+ else
67
+ managedServers.delete(server);
68
+ // Event callbacks cannot report a rejection; handle.close() still awaits/reports it.
69
+ if (publication)
70
+ void unpublish().catch(() => { });
71
+ };
72
+ const removeSetupListeners = () => {
73
+ server.removeListener('listening', onListening);
74
+ server.removeListener('error', onError);
75
+ options.signal?.removeEventListener('abort', onAbort);
76
+ };
77
+ const closeServer = () => new Promise((resolve, reject) => {
78
+ // Calling close also cancels an in-progress DNS/bind attempt. Do not merely test
79
+ // server.listening: it is false while listen is still acquiring its socket.
80
+ try {
81
+ server.close((error) => {
82
+ if (error && error.code !== 'ERR_SERVER_NOT_RUNNING')
83
+ reject(error);
84
+ else
85
+ resolve();
86
+ });
87
+ }
88
+ catch (error) {
89
+ reject(error);
90
+ }
91
+ });
92
+ try {
93
+ const bindings = await endpoints.list(options);
94
+ const binding = Array.isArray(bindings) ? bindings.find((item) => item?.id === id) : undefined;
95
+ if (!binding)
96
+ throw new ProgramError('NOT_FOUND', `Endpoint ${id} is not configured`);
97
+ if (typeof binding.bindHost !== 'string' || !binding.bindHost || !Number.isSafeInteger(binding.requestedPort) || binding.requestedPort < 0 || binding.requestedPort > 65535 || !['http', 'https'].includes(binding.protocol))
98
+ throw new ProgramError('INVALID_RESPONSE', 'Invalid endpoint binding configuration');
99
+ if (options.signal?.aborted)
100
+ throw cancelled();
101
+ // Do not take ownership of a server that somebody bound while list was pending.
102
+ if (server.listening)
103
+ throw new ProgramError('BUSY', 'Endpoint server was bound during configuration lookup');
104
+ server.once('listening', onListening);
105
+ server.on('error', onError);
106
+ server.once('close', onClose);
107
+ options.signal?.addEventListener('abort', onAbort, { once: true });
108
+ attemptedBind = true;
109
+ server.listen({ port: binding.requestedPort, host: unbracket(binding.bindHost) });
110
+ await Promise.race([listening, interrupted]);
111
+ if (setupFailed)
112
+ throw setupError;
113
+ if (options.signal?.aborted)
114
+ throw cancelled();
115
+ if (closed || !server.listening)
116
+ throw unavailable();
117
+ const address = server.address();
118
+ if (!address || typeof address === 'string' || !Number.isSafeInteger(address.port) || address.port < 1 || address.port > 65535)
119
+ throw new ProgramError('UNAVAILABLE', 'Endpoint server did not bind a TCP port');
120
+ port = address.port;
121
+ publication = endpoints.publish(id, { port }, options);
122
+ await Promise.race([publication, interrupted]);
123
+ if (setupFailed)
124
+ throw setupError;
125
+ if (options.signal?.aborted)
126
+ throw cancelled();
127
+ if (closed || !server.listening)
128
+ throw unavailable();
129
+ setupComplete = true;
130
+ removeSetupListeners();
131
+ let localHost = unbracket(binding.bindHost);
132
+ if (localHost === '0.0.0.0')
133
+ localHost = '127.0.0.1';
134
+ else if (localHost === '::')
135
+ localHost = '::1';
136
+ if (localHost.includes(':'))
137
+ localHost = `[${localHost}]`;
138
+ return {
139
+ port,
140
+ host: binding.bindHost,
141
+ localUrl: `${binding.protocol}://${localHost}:${port}/`,
142
+ close: () => closing ??= (async () => {
143
+ if (!closed)
144
+ await closeServer();
145
+ await unpublish();
146
+ })(),
147
+ };
148
+ }
149
+ catch (error) {
150
+ setupComplete = true;
151
+ removeSetupListeners();
152
+ // Publish failures/cancellation have potentially unknown effects, so compensate
153
+ // once with the exact port. A failed bind never publishes or unpublishes.
154
+ if (attemptedBind && !closed)
155
+ await closeServer().catch(() => { });
156
+ await unpublish().catch(() => { });
157
+ server.removeListener('close', onClose);
158
+ managedServers.delete(server);
159
+ throw error;
160
+ }
161
+ }
162
+ //# sourceMappingURL=endpoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoints.js","sourceRoot":"","sources":["../../src/app/endpoints.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { JsonValue } from '../types.js';
2
+ import { ProgramError } from '../runtime/protocol.js';
3
+ import type { CallOptions } from './index.js';
4
+ import type { InboxMessage, MessageReceipt, ReceiveOptions } from './mailbox.js';
5
+ export type InboxBridgeCall = <T = JsonValue>(method: string, input?: JsonValue, options?: CallOptions) => Promise<T>;
6
+ export interface InboxReceiveOptions extends ReceiveOptions, CallOptions {
7
+ }
8
+ export interface ManagedReceiveOptions extends InboxReceiveOptions {
9
+ /** Callback deadline, independently of individual bridge calls. Default 120s; maximum 1h. */
10
+ processingTimeoutMs?: number;
11
+ }
12
+ export type ReadonlyInboxJson = string | number | boolean | null | readonly ReadonlyInboxJson[] | {
13
+ readonly [key: string]: ReadonlyInboxJson;
14
+ };
15
+ /** The callback cannot access the claim token or any settlement operation. */
16
+ export type HandlerMessage = Readonly<Omit<InboxMessage, 'leaseToken' | 'body' | 'receipt'>> & {
17
+ readonly body: ReadonlyInboxJson;
18
+ readonly receipt: Readonly<MessageReceipt>;
19
+ };
20
+ export interface InboxHandlerContext {
21
+ readonly signal: AbortSignal;
22
+ }
23
+ export type InboxHandler<R> = (message: HandlerMessage, context: InboxHandlerContext) => R | PromiseLike<R>;
24
+ type Claim = Pick<InboxMessage, 'id' | 'leaseToken'>;
25
+ export interface ProgramInbox {
26
+ receive<R>(handler: InboxHandler<R>): Promise<R | null>;
27
+ receive<R>(options: ManagedReceiveOptions | undefined, handler: InboxHandler<R>): Promise<R | null>;
28
+ /** @deprecated Prefer receive(options, handler), which owns renewal and settlement. */
29
+ receive(options?: InboxReceiveOptions): Promise<InboxMessage | null>;
30
+ /** Low-level manual claim: the caller must renew and settle its own live lease. */
31
+ claim(options?: InboxReceiveOptions): Promise<InboxMessage | null>;
32
+ /** Low-level renewal, fenced by the exact live claim token and run. */
33
+ renew(message: Claim, leaseMs: number, options?: CallOptions): Promise<MessageReceipt>;
34
+ /** Low-level, single-attempt ACK. A rejected call may already have committed. */
35
+ ack(message: Claim | string, leaseToken?: string, options?: CallOptions): Promise<MessageReceipt>;
36
+ /** Low-level, single-attempt NACK. Requires the exact, unexpired claim. */
37
+ nack(message: Claim | string, leaseToken?: string, options?: CallOptions): Promise<MessageReceipt>;
38
+ /** Low-level durable status lookup; acceptance is not successful processing. */
39
+ receipt(id: string, options?: CallOptions): Promise<MessageReceipt | null>;
40
+ }
41
+ /** ACK may have committed before its response was lost. Neither retry nor NACK is safe. */
42
+ export declare class SettlementUnknownError extends ProgramError {
43
+ readonly messageId: string;
44
+ readonly outcome: "unknown";
45
+ readonly operation: "ack";
46
+ readonly cause: unknown;
47
+ constructor(messageId: string, cause: unknown);
48
+ }
49
+ /**
50
+ * Managed processing invokes the callback once per claim, renews while it runs, and ACKs
51
+ * only a fulfilled, uninterrupted callback. No bridge effect or callback is retried.
52
+ *
53
+ * This is NOT exactly-once processing: crashes, lease loss, and uncooperative callbacks
54
+ * can cause redelivery and overlapping external effects. Use application idempotency.
55
+ * Cancellation rejects receive promptly but does not NACK a still-running callback.
56
+ * Its claim is renewed only until the processing deadline; then renewal stops and the
57
+ * last lease expires naturally. A late callback never ACKs. Each helper retains one
58
+ * of its 32 slots until the actual callback settles, even after the caller has left.
59
+ */
60
+ export declare function createProgramInbox(call: InboxBridgeCall): ProgramInbox;
61
+ export {};