@2kw/ai-mcp-server 6.3.0-dev.8 → 6.3.0-dev.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,6 +42,7 @@ Get an API key from your [2kw.ai dashboard](https://2kw.ai) — paid plans start
42
42
  |----------|----------|---------|-------------|
43
43
  | `AI_2KW_API_KEY` | Yes | — | API key for the 2kw.ai platform (legacy alias: `BACKBONE_API_KEY`) |
44
44
  | `AI_2KW_BASE_URL` | No | 2kw.ai cloud API | Point at a self-hosted deployment (legacy alias: `BACKBONE_BASE_URL`) |
45
+ | `AI_2KW_MEMORY` | No | off | `true` makes agent runs through `2kw_create_response` and `2kw_decide_agent_approvals` opt into agent memory (`X-Backbone-Memory: enabled`) |
45
46
  | `MCP_TRANSPORT` | No | `stdio` | Transport mode: `stdio` or `http` |
46
47
  | `MCP_HTTP_PORT` | No | `3100` | Port for HTTP transport |
47
48
 
@@ -56,10 +57,11 @@ Get an API key from your [2kw.ai dashboard](https://2kw.ai) — paid plans start
56
57
  | **Schemas** | CRUD, versioning, labels, validation, and testing against sample documents |
57
58
  | **Prompts** | Versioned prompt management, labels, compilation, testing |
58
59
  | **Datasets & experiments** | Build datasets, run experiments, manage evaluators, record scores |
59
- | **Agents** | CRUD, versioning, labels, tool-approval history, and tool-catalog sync history |
60
+ | **Agents** | CRUD, versioning, labels, runs with the full result envelope, approval decisions, tool-approval history, and tool-catalog sync history |
60
61
  | **Conversations** | Create/inspect/delete conversations and replay their items for the responses API |
61
62
  | **Knowledge base** | CRUD, document upload/attach/versioning, hybrid search, and citation resolution |
62
63
  | **Files** | Upload, list, download, and delete files (agent input or knowledge documents) |
64
+ | **Memory** | List, read, write and delete your own agent memory files, forget everything; admins see member totals and erase a member |
63
65
  | **Observability** | Analytics (spend, quality, providers, errors), traces, billing limits |
64
66
  | **API docs** | Browse the platform API documentation by section |
65
67
 
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import createClient from "openapi-fetch";
1
+ import createClient, { type Middleware } from "openapi-fetch";
2
2
  import type { paths } from "./generated/openapi.js";
3
3
  export type ApiClient = ReturnType<typeof createClient<paths>> & {
4
4
  /** Exposed config for raw fetch calls (e.g. multipart uploads). */
@@ -7,8 +7,15 @@ export type ApiClient = ReturnType<typeof createClient<paths>> & {
7
7
  apiKey: string;
8
8
  };
9
9
  };
10
+ /** The per-request opt-in to agent memory for API-key runs (agent memory spec §3.3, D6, D7). */
11
+ export declare const MEMORY_HEADER = "X-Backbone-Memory";
12
+ /** Adds `X-Backbone-Memory: enabled` to `POST …/v1/responses` only, the call that starts or resumes a run. */
13
+ export declare const memoryHeaderMiddleware: Middleware;
10
14
  /**
11
15
  * Create a typed openapi-fetch client with Bearer auth and error middleware.
16
+ * `memory: true` opts agent runs into agent memory (see {@link memoryHeaderMiddleware}).
12
17
  */
13
- export declare function createApiClient(baseUrl: string, apiKey: string): ApiClient;
18
+ export declare function createApiClient(baseUrl: string, apiKey: string, options?: {
19
+ memory?: boolean;
20
+ }): ApiClient;
14
21
  //# sourceMappingURL=client.d.ts.map
package/dist/client.js CHANGED
@@ -34,10 +34,22 @@ const errorMiddleware = {
34
34
  });
35
35
  },
36
36
  };
37
+ /** The per-request opt-in to agent memory for API-key runs (agent memory spec §3.3, D6, D7). */
38
+ export const MEMORY_HEADER = "X-Backbone-Memory";
39
+ /** Adds `X-Backbone-Memory: enabled` to `POST …/v1/responses` only, the call that starts or resumes a run. */
40
+ export const memoryHeaderMiddleware = {
41
+ onRequest({ request }) {
42
+ if (request.method === "POST" && new URL(request.url).pathname.endsWith("/v1/responses")) {
43
+ request.headers.set(MEMORY_HEADER, "enabled");
44
+ }
45
+ return request;
46
+ },
47
+ };
37
48
  /**
38
49
  * Create a typed openapi-fetch client with Bearer auth and error middleware.
50
+ * `memory: true` opts agent runs into agent memory (see {@link memoryHeaderMiddleware}).
39
51
  */
40
- export function createApiClient(baseUrl, apiKey) {
52
+ export function createApiClient(baseUrl, apiKey, options = {}) {
41
53
  const client = createClient({
42
54
  baseUrl: baseUrl.replace(/\/+$/, ""),
43
55
  headers: {
@@ -45,6 +57,8 @@ export function createApiClient(baseUrl, apiKey) {
45
57
  },
46
58
  });
47
59
  client.use(errorMiddleware);
60
+ if (options.memory)
61
+ client.use(memoryHeaderMiddleware);
48
62
  // Expose config for raw fetch calls (multipart uploads)
49
63
  const enriched = client;
50
64
  enriched._config = { baseUrl: baseUrl.replace(/\/+$/, ""), apiKey };
package/dist/index.js CHANGED
@@ -6,31 +6,7 @@ import { createServer } from "node:http";
6
6
  import { createRequire } from "node:module";
7
7
  import { createApiClient } from "./client.js";
8
8
  const pkg = createRequire(import.meta.url)("../package.json");
9
- import * as conversion from "./tools/conversion.js";
10
- import * as extraction from "./tools/extraction.js";
11
- import * as aiGateway from "./tools/ai-gateway.js";
12
- import * as transcription from "./tools/transcription.js";
13
- import * as schemas from "./tools/schemas.js";
14
- import * as schemaLabels from "./tools/schema-labels.js";
15
- import * as schemaVersions from "./tools/schema-versions.js";
16
- import * as schemaTesting from "./tools/schema-testing.js";
17
- import * as datasets from "./tools/datasets.js";
18
- import * as experiments from "./tools/experiments.js";
19
- import * as evaluators from "./tools/evaluators.js";
20
- import * as prompts from "./tools/prompts.js";
21
- import * as skills from "./tools/skills.js";
22
- import * as plugins from "./tools/plugins.js";
23
- import * as providers from "./tools/providers.js";
24
- import * as billing from "./tools/billing.js";
25
- import * as scores from "./tools/scores.js";
26
- import * as annotationQueues from "./tools/annotation-queues.js";
27
- import * as tracing from "./tools/tracing.js";
28
- import * as analytics from "./tools/analytics.js";
29
- import * as docs from "./tools/docs.js";
30
- import * as agents from "./tools/agents.js";
31
- import * as conversations from "./tools/conversations.js";
32
- import * as knowledge from "./tools/knowledge.js";
33
- import * as files from "./tools/files.js";
9
+ import { registerAllTools } from "./tools/index.js";
34
10
  // Read the canonical KW_* env var; fall back to legacy BACKBONE_* for
35
11
  // backwards compatibility. Warn once on stderr when the legacy name supplied
36
12
  // the value.
@@ -61,43 +37,19 @@ function requireEnv(canonical, legacy) {
61
37
  }
62
38
  const DEFAULT_BASE_URL = process.env.AI_2KW_DEFAULT_BASE_URL ??
63
39
  process.env.BACKBONE_DEFAULT_BASE_URL ??
64
- "https://backbone.manfred-kunze.dev/api";
40
+ "https://api.2kw.ai";
65
41
  async function main() {
66
42
  const apiKey = requireEnv("AI_2KW_API_KEY", "BACKBONE_API_KEY");
67
43
  const baseUrl = readEnv("AI_2KW_BASE_URL", "BACKBONE_BASE_URL") ?? DEFAULT_BASE_URL;
68
44
  const transport = process.env.MCP_TRANSPORT ?? "stdio";
69
45
  const httpPort = parseInt(process.env.MCP_HTTP_PORT ?? "3100", 10);
70
- const client = createApiClient(baseUrl, apiKey);
46
+ // Opt API-key runs into agent memory (X-Backbone-Memory: enabled on responses calls, #721).
47
+ const client = createApiClient(baseUrl, apiKey, { memory: process.env.AI_2KW_MEMORY === "true" });
71
48
  const server = new McpServer({
72
49
  name: "2kw",
73
50
  version: pkg.version,
74
51
  });
75
- // Register all tool groups
76
- conversion.register(server, client);
77
- extraction.register(server, client);
78
- aiGateway.register(server, client);
79
- transcription.register(server, client);
80
- schemas.register(server, client);
81
- schemaLabels.register(server, client);
82
- schemaVersions.register(server, client);
83
- schemaTesting.register(server, client);
84
- datasets.register(server, client);
85
- experiments.register(server, client);
86
- evaluators.register(server, client);
87
- prompts.register(server, client);
88
- skills.register(server, client);
89
- plugins.register(server, client);
90
- providers.register(server, client);
91
- billing.register(server, client);
92
- scores.register(server, client);
93
- annotationQueues.register(server, client);
94
- tracing.register(server, client);
95
- analytics.register(server, client);
96
- docs.register(server, client, baseUrl, apiKey);
97
- agents.register(server, client);
98
- conversations.register(server, client);
99
- knowledge.register(server, client);
100
- files.register(server, client);
52
+ registerAllTools(server, { client, baseUrl, apiKey });
101
53
  if (transport === "http") {
102
54
  const httpTransport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
103
55
  const httpServer = createServer(async (req, res) => {
@@ -0,0 +1,54 @@
1
+ import type { ApiClient } from "../client.js";
2
+ import type { components } from "../generated/openapi.js";
3
+ import { type ConversationMode, type ResponsesResult } from "./agent-run.js";
4
+ /**
5
+ * Decide the approvals a paused agent run is waiting for (#667; spec 2026-09-14-cli-agents-design.md
6
+ * §4.2, D10, D11). Mirrors `cli/src/lib/agent-decide.ts` and `agent-lookup.ts`, with a per-approval
7
+ * input instead of the CLI's flags.
8
+ */
9
+ export type ApprovalRow = components["schemas"]["ToolApprovalDTO"];
10
+ export interface DecisionInput {
11
+ approvalId: string;
12
+ decision: "approve" | "reject";
13
+ reason?: string;
14
+ remember?: boolean;
15
+ }
16
+ export interface DecideInput {
17
+ decisions?: DecisionInput[];
18
+ decideAll?: "approve" | "reject";
19
+ /** Only with `decideAll`: the reason stored on every decision. */
20
+ reason?: string;
21
+ /** Only with `decideAll`: remember every approval for the conversation. */
22
+ remember?: boolean;
23
+ }
24
+ /** The #660 wire item, byte for byte what n8n Decide Approval and `bb agents decide` send. */
25
+ export interface ApprovalItem {
26
+ type: "backbone:approval_response";
27
+ approval_id: string;
28
+ decision: "approve" | "reject";
29
+ hmac: string;
30
+ reason?: string;
31
+ remember?: "conversation";
32
+ }
33
+ /** `name[@label][#model]`, split like the server: the model at the last `#`, then the label at the last `@`. */
34
+ export declare function splitAgentRef(ref: string): {
35
+ name: string;
36
+ label: string | undefined;
37
+ model: string | undefined;
38
+ };
39
+ /** A UUID is taken as the id; a name is matched exactly (the REST API only offers a substring `search`). */
40
+ export declare function resolveAgentId(client: ApiClient, name: string): Promise<string>;
41
+ export declare function fetchPendingApprovals(client: ApiClient, agentId: string, responseId: string): Promise<ApprovalRow[]>;
42
+ /**
43
+ * The backend refuses a continuation that leaves any pending approval of the paused response
44
+ * undecided (400 incomplete_tool_outputs, D10), so the whole set is checked here before sending.
45
+ */
46
+ export declare function planDecisions(pending: ApprovalRow[], input: DecideInput, responseId: string): ApprovalItem[];
47
+ /**
48
+ * Continues on `agent/<agentId>[@<label>][#<model>]`: the server resolves the continuation's tools,
49
+ * instructions and model from this reference, so label and model must be the run's (D11). Never the
50
+ * echoed `name@<versionNumber>` — it would 404 as a label.
51
+ * With `mode`, the `backbone:mode` item follows the decisions (#656).
52
+ */
53
+ export declare function continueWithDecisions(client: ApiClient, agentId: string, responseId: string, items: ApprovalItem[], label?: string, model?: string, mode?: ConversationMode): Promise<ResponsesResult>;
54
+ //# sourceMappingURL=agent-decide.d.ts.map
@@ -0,0 +1,124 @@
1
+ import { modeItem } from "./agent-run.js";
2
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3
+ const PAGE_SIZE = 100;
4
+ const MAX_PAGES = 50;
5
+ /** `name[@label][#model]`, split like the server: the model at the last `#`, then the label at the last `@`. */
6
+ export function splitAgentRef(ref) {
7
+ const hash = ref.lastIndexOf("#");
8
+ const model = hash >= 0 ? ref.slice(hash + 1) : undefined;
9
+ const base = hash >= 0 ? ref.slice(0, hash) : ref;
10
+ const at = base.lastIndexOf("@");
11
+ if (at <= 0)
12
+ return { name: base, label: undefined, model };
13
+ return { name: base.slice(0, at), label: base.slice(at + 1), model };
14
+ }
15
+ /** A UUID is taken as the id; a name is matched exactly (the REST API only offers a substring `search`). */
16
+ export async function resolveAgentId(client, name) {
17
+ if (UUID.test(name))
18
+ return name;
19
+ for (let page = 0; page < MAX_PAGES; page++) {
20
+ const { data } = await client.GET("/v1/agents", {
21
+ // A stable sort: offset paging over an unordered result can skip rows between pages.
22
+ params: { query: { search: name, pageable: { page, size: PAGE_SIZE, sort: ["id,asc"] } } },
23
+ });
24
+ // Typed loosely, as 2kw_list_agents does: the generated page type of this endpoint is not a PageAgentDTO.
25
+ const pageData = data;
26
+ const content = pageData?.content ?? [];
27
+ const hit = content.find((a) => a.name === name);
28
+ if (hit?.id)
29
+ return String(hit.id);
30
+ if (pageData?.last !== false || content.length === 0)
31
+ break;
32
+ }
33
+ throw new Error(`Agent '${name}' not found. List agents with 2kw_list_agents.`);
34
+ }
35
+ export async function fetchPendingApprovals(client, agentId, responseId) {
36
+ const rows = [];
37
+ for (let page = 0; page < MAX_PAGES; page++) {
38
+ const { data } = await client.GET("/v1/agents/{agentId}/approvals", {
39
+ params: { path: { agentId }, query: { status: "pending", pageable: { page, size: PAGE_SIZE } } },
40
+ });
41
+ const content = data?.content ?? [];
42
+ rows.push(...content.filter((r) => r.responseId === responseId));
43
+ if (data?.last !== false || content.length === 0)
44
+ break;
45
+ }
46
+ return rows;
47
+ }
48
+ /**
49
+ * The backend refuses a continuation that leaves any pending approval of the paused response
50
+ * undecided (400 incomplete_tool_outputs, D10), so the whole set is checked here before sending.
51
+ */
52
+ export function planDecisions(pending, input, responseId) {
53
+ if (pending.length === 0) {
54
+ throw new Error(`No pending approvals for ${responseId} (already decided or superseded).`);
55
+ }
56
+ const hasList = input.decisions !== undefined && input.decisions.length > 0;
57
+ if (hasList === (input.decideAll !== undefined)) {
58
+ throw new Error("Give either `decisions` or `decideAll` (exactly one): one decision per pending approval, or one for all.");
59
+ }
60
+ const chosen = new Map();
61
+ if (input.decideAll !== undefined) {
62
+ for (const r of pending) {
63
+ chosen.set(String(r.id), { approvalId: String(r.id), decision: input.decideAll, reason: input.reason, remember: input.remember });
64
+ }
65
+ }
66
+ else {
67
+ const twice = new Set();
68
+ for (const d of input.decisions) {
69
+ if (chosen.has(d.approvalId))
70
+ twice.add(d.approvalId);
71
+ chosen.set(d.approvalId, d);
72
+ }
73
+ if (twice.size)
74
+ throw new Error(`Approvals decided more than once: ${[...twice].join(", ")}`);
75
+ const pendingIds = new Set(pending.map((r) => String(r.id)));
76
+ const foreign = [...chosen.keys()].filter((id) => !pendingIds.has(id));
77
+ if (foreign.length)
78
+ throw new Error(`Not pending on ${responseId}: ${foreign.join(", ")}`);
79
+ const undecided = [...pendingIds].filter((id) => !chosen.has(id));
80
+ if (undecided.length) {
81
+ throw new Error(`Every pending approval of a response must be decided in one call. Undecided: ${undecided.join(", ")}`);
82
+ }
83
+ }
84
+ return pending.map((r) => {
85
+ const id = String(r.id);
86
+ const d = chosen.get(id);
87
+ if (d.remember && d.decision !== "approve") {
88
+ throw new Error(`\`remember\` applies only to an approve: ${id}`);
89
+ }
90
+ if (d.remember && (r.policyClass ?? "").toUpperCase() === "DESTRUCTIVE") {
91
+ throw new Error(`\`remember\` cannot be used on a destructive tool call: ${id}`);
92
+ }
93
+ if (!r.hmac)
94
+ throw new Error(`Approval ${id} carries no hmac and cannot be decided here.`);
95
+ return {
96
+ type: "backbone:approval_response",
97
+ approval_id: id,
98
+ decision: d.decision,
99
+ hmac: r.hmac,
100
+ ...(d.reason ? { reason: d.reason } : {}),
101
+ ...(d.remember ? { remember: "conversation" } : {}),
102
+ };
103
+ });
104
+ }
105
+ /**
106
+ * Continues on `agent/<agentId>[@<label>][#<model>]`: the server resolves the continuation's tools,
107
+ * instructions and model from this reference, so label and model must be the run's (D11). Never the
108
+ * echoed `name@<versionNumber>` — it would 404 as a label.
109
+ * With `mode`, the `backbone:mode` item follows the decisions (#656).
110
+ */
111
+ export async function continueWithDecisions(client, agentId, responseId, items, label, model, mode) {
112
+ const body = {
113
+ model: `agent/${agentId}${label ? `@${label}` : ""}${model ? `#${model}` : ""}`,
114
+ previous_response_id: responseId,
115
+ stream: false,
116
+ // With `mode`, the backbone:mode item follows the decisions (#656 D7); without it, nothing is added (D2).
117
+ input: mode ? [...items, modeItem(mode)] : items,
118
+ };
119
+ // The generated body type does not model backbone: extension items, hence the cast.
120
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
+ const { data } = await client.POST("/v1/responses", { body });
122
+ return data;
123
+ }
124
+ //# sourceMappingURL=agent-decide.js.map
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The run envelope of `bb agents run --json` (spec 2026-09-14-cli-agents-design.md §4.3), copied
3
+ * from `cli/src/lib/agent-run.ts` because cli/ and mcp/ share no package (#667). Keep the two in step;
4
+ * only the text of `next` differs, because an MCP caller decides through a tool, not a shell command.
5
+ */
6
+ type AnyRecord = Record<string, any>;
7
+ export type RunStatus = "completed" | "requires_approval" | "requires_tool_output" | "incomplete";
8
+ export interface PendingApproval {
9
+ approvalId: string;
10
+ callId: string;
11
+ tool: string;
12
+ arguments: unknown;
13
+ policyClass: string;
14
+ /** Why the automatic approver escalated this request to a human (#634); null when it did not. */
15
+ reason: string | null;
16
+ }
17
+ export interface ToolCallSummary {
18
+ tool: string;
19
+ callId: string;
20
+ /** `incomplete` when the server-side tool run failed (its `function_call_output` carries that status). */
21
+ status: "completed" | "incomplete";
22
+ }
23
+ export interface PendingToolCall {
24
+ tool: string;
25
+ callId: string;
26
+ arguments: unknown;
27
+ }
28
+ /**
29
+ * A connector the run waits for the user to connect, allow or reconnect in chat.2kw.ai: an open
30
+ * `backbone:connector_auth_request` (#807 R12). The caller never answers the connect call; the
31
+ * continuation re-checks access itself.
32
+ */
33
+ export interface PendingConnection {
34
+ serverLabel: string;
35
+ host: string;
36
+ /** `connect`, `allow` or `reconnect`. */
37
+ reason: string;
38
+ /** The egress difference an allow is re-asked for; absent otherwise. */
39
+ destinations?: string[];
40
+ }
41
+ /** Fallback chat.2kw.ai origin when the API host is not one we recognise. */
42
+ export declare const DEFAULT_CHAT_URL = "https://chat.2kw.ai";
43
+ /**
44
+ * The chat web host that belongs to the server's API base URL (`AI_2KW_BASE_URL`), where a member
45
+ * connects a connector. `AI_2KW_CHAT_URL` overrides the mapping; a trailing slash is dropped.
46
+ */
47
+ export declare function chatUrlFor(baseUrl: string | undefined, env?: NodeJS.ProcessEnv): string;
48
+ /** The end user's conversation mode (epic &59); the server matches these three values exactly. */
49
+ export type ConversationMode = "plan" | "ask" | "auto";
50
+ export declare const CONVERSATION_MODES: readonly ConversationMode[];
51
+ /**
52
+ * Who may change the mode (#656 D8), stated in both tool descriptions: the mode outlives the request
53
+ * that sets it, so a model that switched on its own would lift the user's choice for every later turn.
54
+ */
55
+ export declare const MODE_RULE: string;
56
+ /** The `backbone:mode` input item (S1 D7); always appended last. */
57
+ export declare function modeItem(mode: ConversationMode): {
58
+ type: "backbone:mode";
59
+ mode: ConversationMode;
60
+ };
61
+ /**
62
+ * The mode the response ran under (`conversation_mode`, #656). An absent key (a server before #656)
63
+ * and any value other than the three read as null, which also means "none set".
64
+ */
65
+ export declare function responseMode(result: ResponsesResult | undefined): ConversationMode | null;
66
+ export interface RunEnvelope {
67
+ status: RunStatus;
68
+ /** The conversation mode the request ran under (`conversation_mode`); null when none is set. */
69
+ mode: ConversationMode | null;
70
+ agent: string | null;
71
+ version: number | null;
72
+ responseId: string | null;
73
+ conversationId: string | null;
74
+ text: string;
75
+ toolCalls: ToolCallSummary[];
76
+ pendingApprovals: PendingApproval[];
77
+ pendingToolCalls: PendingToolCall[];
78
+ pendingConnections: PendingConnection[];
79
+ incompleteReason: string | null;
80
+ usage: {
81
+ inputTokens: number;
82
+ outputTokens: number;
83
+ } | null;
84
+ next: string | null;
85
+ }
86
+ /** Loose wire shape of a `POST /v1/responses` result; the OpenAPI spec types it as `object`. */
87
+ export interface ResponsesResult {
88
+ id?: string;
89
+ status?: string;
90
+ model?: string;
91
+ output?: AnyRecord[];
92
+ usage?: {
93
+ input_tokens?: number;
94
+ output_tokens?: number;
95
+ total_tokens?: number;
96
+ };
97
+ conversation?: {
98
+ id?: string;
99
+ } | null;
100
+ incomplete_details?: {
101
+ reason?: string;
102
+ } | null;
103
+ conversation_mode?: string | null;
104
+ }
105
+ /** The assistant's text: every `output_text` part of every `message` item, in order. */
106
+ export declare function extractResponseText(result: ResponsesResult | undefined): string;
107
+ /**
108
+ * The response echoes `model` as `agent/{name}@{versionNumber}` (all digits), optionally
109
+ * followed by a `#<model>` override. Only a trailing all-digit `@N` is read as a version;
110
+ * any other `@` suffix stays part of the name.
111
+ */
112
+ export declare function parseAgentModel(model?: string): {
113
+ agent: string | null;
114
+ version: number | null;
115
+ };
116
+ /**
117
+ * @param agentRef the reference the run was started with (`name[@label][#model]`); `next` names it so
118
+ * the decision continues on the same label and model (D11). Falls back to the echoed agent name.
119
+ * @param chatUrl the chat web host of the API ({@link chatUrlFor}); a connect pause's `next` names its
120
+ * Connectors page.
121
+ */
122
+ export declare function buildRunEnvelope(result: ResponsesResult | undefined, agentRef?: string, chatUrl?: string): RunEnvelope;
123
+ export {};
124
+ //# sourceMappingURL=agent-run.d.ts.map