@koda-sl/baker-bridge 0.118.0-dev.fc1af4da8 → 0.119.0-dev.4248c4e66

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 (143) hide show
  1. package/README.md +2 -17
  2. package/dist/hono/agent-session.d.ts +0 -3
  3. package/dist/hono/agent-session.d.ts.map +1 -1
  4. package/dist/hono/agent-session.js +0 -15
  5. package/dist/hono/agent-session.js.map +1 -1
  6. package/dist/hono/agent.d.ts +0 -2
  7. package/dist/hono/agent.d.ts.map +1 -1
  8. package/dist/hono/agent.js +3 -10
  9. package/dist/hono/agent.js.map +1 -1
  10. package/dist/hono/baker-ui-tool-schemas.test.js +0 -5
  11. package/dist/hono/baker-ui-tool-schemas.test.js.map +1 -1
  12. package/dist/hono/bridge-job.d.ts +30 -14
  13. package/dist/hono/bridge-job.d.ts.map +1 -1
  14. package/dist/hono/bridge-job.js +77 -71
  15. package/dist/hono/bridge-job.js.map +1 -1
  16. package/dist/hono/bridge-job.test.js +96 -78
  17. package/dist/hono/bridge-job.test.js.map +1 -1
  18. package/dist/hono/connection-input.d.ts +147 -11
  19. package/dist/hono/connection-input.d.ts.map +1 -1
  20. package/dist/hono/connection-input.js +127 -13
  21. package/dist/hono/connection-input.js.map +1 -1
  22. package/dist/hono/connection-input.test.js +61 -1
  23. package/dist/hono/connection-input.test.js.map +1 -1
  24. package/dist/hono/convex.d.ts +0 -8
  25. package/dist/hono/convex.d.ts.map +1 -1
  26. package/dist/hono/convex.js +0 -8
  27. package/dist/hono/convex.js.map +1 -1
  28. package/dist/hono/mcp-servers.d.ts +8 -1
  29. package/dist/hono/mcp-servers.d.ts.map +1 -1
  30. package/dist/hono/mcp-servers.js +17 -6
  31. package/dist/hono/mcp-servers.js.map +1 -1
  32. package/dist/hono/mcp-servers.test.js +25 -0
  33. package/dist/hono/mcp-servers.test.js.map +1 -1
  34. package/dist/hono/prompt-context.d.ts +1 -8
  35. package/dist/hono/prompt-context.d.ts.map +1 -1
  36. package/dist/hono/prompt-context.js +7 -45
  37. package/dist/hono/prompt-context.js.map +1 -1
  38. package/dist/hono/prompt-context.test.js +1 -32
  39. package/dist/hono/prompt-context.test.js.map +1 -1
  40. package/dist/hono/relay.d.ts +1 -10
  41. package/dist/hono/relay.d.ts.map +1 -1
  42. package/dist/hono/relay.js +0 -6
  43. package/dist/hono/relay.js.map +1 -1
  44. package/dist/hono/server.d.ts.map +1 -1
  45. package/dist/hono/server.js +0 -22
  46. package/dist/hono/server.js.map +1 -1
  47. package/dist/hono/tag-input.d.ts +3 -83
  48. package/dist/hono/tag-input.d.ts.map +1 -1
  49. package/dist/hono/tag-input.js +17 -23
  50. package/dist/hono/tag-input.js.map +1 -1
  51. package/dist/hono/tag-input.test.js +1 -15
  52. package/dist/hono/tag-input.test.js.map +1 -1
  53. package/dist/hono/types.d.ts +0 -8
  54. package/dist/hono/types.d.ts.map +1 -1
  55. package/package.json +2 -5
  56. package/dist/broker/baker-api.d.ts +0 -14
  57. package/dist/broker/baker-api.d.ts.map +0 -1
  58. package/dist/broker/baker-api.js +0 -41
  59. package/dist/broker/baker-api.js.map +0 -1
  60. package/dist/broker/broker-client.d.ts +0 -10
  61. package/dist/broker/broker-client.d.ts.map +0 -1
  62. package/dist/broker/broker-client.js +0 -60
  63. package/dist/broker/broker-client.js.map +0 -1
  64. package/dist/broker/ca.d.ts +0 -30
  65. package/dist/broker/ca.d.ts.map +0 -1
  66. package/dist/broker/ca.js +0 -69
  67. package/dist/broker/ca.js.map +0 -1
  68. package/dist/broker/ca.test.d.ts +0 -2
  69. package/dist/broker/ca.test.d.ts.map +0 -1
  70. package/dist/broker/ca.test.js +0 -42
  71. package/dist/broker/ca.test.js.map +0 -1
  72. package/dist/broker/credential-cache.d.ts +0 -29
  73. package/dist/broker/credential-cache.d.ts.map +0 -1
  74. package/dist/broker/credential-cache.js +0 -36
  75. package/dist/broker/credential-cache.js.map +0 -1
  76. package/dist/broker/credential-cache.test.d.ts +0 -2
  77. package/dist/broker/credential-cache.test.d.ts.map +0 -1
  78. package/dist/broker/credential-cache.test.js +0 -74
  79. package/dist/broker/credential-cache.test.js.map +0 -1
  80. package/dist/broker/credential-text.d.ts +0 -45
  81. package/dist/broker/credential-text.d.ts.map +0 -1
  82. package/dist/broker/credential-text.js +0 -100
  83. package/dist/broker/credential-text.js.map +0 -1
  84. package/dist/broker/credential-text.test.d.ts +0 -2
  85. package/dist/broker/credential-text.test.d.ts.map +0 -1
  86. package/dist/broker/credential-text.test.js +0 -52
  87. package/dist/broker/credential-text.test.js.map +0 -1
  88. package/dist/broker/env.d.ts +0 -19
  89. package/dist/broker/env.d.ts.map +0 -1
  90. package/dist/broker/env.js +0 -16
  91. package/dist/broker/env.js.map +0 -1
  92. package/dist/broker/main.d.ts +0 -3
  93. package/dist/broker/main.d.ts.map +0 -1
  94. package/dist/broker/main.js +0 -51
  95. package/dist/broker/main.js.map +0 -1
  96. package/dist/broker/proxy.d.ts +0 -24
  97. package/dist/broker/proxy.d.ts.map +0 -1
  98. package/dist/broker/proxy.integration.test.d.ts +0 -2
  99. package/dist/broker/proxy.integration.test.d.ts.map +0 -1
  100. package/dist/broker/proxy.integration.test.js +0 -128
  101. package/dist/broker/proxy.integration.test.js.map +0 -1
  102. package/dist/broker/proxy.js +0 -137
  103. package/dist/broker/proxy.js.map +0 -1
  104. package/dist/broker/rewrite.d.ts +0 -38
  105. package/dist/broker/rewrite.d.ts.map +0 -1
  106. package/dist/broker/rewrite.js +0 -275
  107. package/dist/broker/rewrite.js.map +0 -1
  108. package/dist/broker/rewrite.test.d.ts +0 -2
  109. package/dist/broker/rewrite.test.d.ts.map +0 -1
  110. package/dist/broker/rewrite.test.js +0 -171
  111. package/dist/broker/rewrite.test.js.map +0 -1
  112. package/dist/broker/socket-service.d.ts +0 -18
  113. package/dist/broker/socket-service.d.ts.map +0 -1
  114. package/dist/broker/socket-service.js +0 -84
  115. package/dist/broker/socket-service.js.map +0 -1
  116. package/dist/broker/socket-service.test.d.ts +0 -2
  117. package/dist/broker/socket-service.test.d.ts.map +0 -1
  118. package/dist/broker/socket-service.test.js +0 -62
  119. package/dist/broker/socket-service.test.js.map +0 -1
  120. package/dist/broker/token-bucket.d.ts +0 -9
  121. package/dist/broker/token-bucket.d.ts.map +0 -1
  122. package/dist/broker/token-bucket.js +0 -18
  123. package/dist/broker/token-bucket.js.map +0 -1
  124. package/dist/broker/usage-reporter.d.ts +0 -18
  125. package/dist/broker/usage-reporter.d.ts.map +0 -1
  126. package/dist/broker/usage-reporter.js +0 -31
  127. package/dist/broker/usage-reporter.js.map +0 -1
  128. package/dist/broker/usage-reporter.test.d.ts +0 -2
  129. package/dist/broker/usage-reporter.test.d.ts.map +0 -1
  130. package/dist/broker/usage-reporter.test.js +0 -20
  131. package/dist/broker/usage-reporter.test.js.map +0 -1
  132. package/dist/hono/credential-input.d.ts +0 -39
  133. package/dist/hono/credential-input.d.ts.map +0 -1
  134. package/dist/hono/credential-input.js +0 -77
  135. package/dist/hono/credential-input.js.map +0 -1
  136. package/dist/hono/credential-scrub.d.ts +0 -41
  137. package/dist/hono/credential-scrub.d.ts.map +0 -1
  138. package/dist/hono/credential-scrub.js +0 -152
  139. package/dist/hono/credential-scrub.js.map +0 -1
  140. package/dist/hono/credential-scrub.test.d.ts +0 -2
  141. package/dist/hono/credential-scrub.test.d.ts.map +0 -1
  142. package/dist/hono/credential-scrub.test.js +0 -105
  143. package/dist/hono/credential-scrub.test.js.map +0 -1
@@ -18,7 +18,6 @@ vi.mock("./runtime-files.ts", async (importOriginal) => {
18
18
  import { AVATAR_CASTING_TOOL_NAME } from "./avatar-casting.js";
19
19
  import { BridgeJobExecutor, createStallDetector, isContextOverflowRefusal, isControlChannelDeny, parsePlanDecision, remapAnswersToQuestionText, } from "./bridge-job.js";
20
20
  import { CONNECTION_INPUT_TOOL_NAME } from "./connection-input.js";
21
- import { CREDENTIAL_INPUT_TOOL_NAME } from "./credential-input.js";
22
21
  import { FLOW_INPUT_TOOL_NAME } from "./flow-input.js";
23
22
  import { bridgeRuntimeFiles } from "./runtime-files.js";
24
23
  import { TAG_INPUT_TOOL_NAME } from "./tag-input.js";
@@ -50,7 +49,6 @@ function activeControls() {
50
49
  pendingTagInputs: new Map(),
51
50
  pendingFlowInputs: new Map(),
52
51
  pendingConnectionInputs: new Map(),
53
- pendingCredentialInputs: new Map(),
54
52
  pendingVoiceCasts: new Map(),
55
53
  pendingAvatarCastings: new Map(),
56
54
  isActive: () => active,
@@ -84,8 +82,6 @@ function recordingRelay() {
84
82
  flowInputResolved: () => Promise.resolve(),
85
83
  connectionInputRequest: () => Promise.resolve(true),
86
84
  connectionInputResolved: () => Promise.resolve(),
87
- credentialInputRequest: () => Promise.resolve(true),
88
- credentialInputResolved: () => Promise.resolve(),
89
85
  avatarCastingRequest: () => Promise.resolve(true),
90
86
  avatarCastingResolved: () => Promise.resolve(),
91
87
  assistantEvent: (target, event, model) => {
@@ -1447,24 +1443,6 @@ describe("BridgeJobExecutor", () => {
1447
1443
  expect(queryInputs[0]?.prompt).toBe("make the headline bigger");
1448
1444
  expect(queryInputs[0]?.reminder).toContain('landing "Homepage" (slug: homepage)');
1449
1445
  });
1450
- it("explains a credential the message names beside it, together with the viewing reference", async () => {
1451
- const queryInputs = [];
1452
- const executor = createExecutor({
1453
- queryInputs,
1454
- queryResults: [scriptedMessages(resultMessage(0, "session_credential"))],
1455
- });
1456
- await executor.execute({
1457
- threadId: "thread_credential",
1458
- turnId: "turn_credential",
1459
- prompt: "log in with user admin and password {{credential:password}}",
1460
- history: history([]),
1461
- currentReference: { type: "landing", slug: "homepage", title: "Homepage" },
1462
- credentials: [{ name: "password", label: "Login password", allowedHosts: [] }],
1463
- }, activeControls());
1464
- expect(queryInputs[0]?.prompt).toBe("log in with user admin and password {{credential:password}}");
1465
- expect(queryInputs[0]?.reminder).toContain('landing "Homepage"');
1466
- expect(queryInputs[0]?.reminder).toContain("`{{credential:password}}` is a credential the user saved");
1467
- });
1468
1446
  it("strips newlines from the viewing reference so a crafted title can't inject instructions", async () => {
1469
1447
  const queryInputs = [];
1470
1448
  const executor = createExecutor({
@@ -2136,93 +2114,135 @@ describe("BridgeJobExecutor", () => {
2136
2114
  expect(connectionRequests).toHaveLength(1);
2137
2115
  expect(decision).toMatchObject({ behavior: "allow" });
2138
2116
  });
2139
- it("turns request_credential away in a Runtime without Credentials", async () => {
2117
+ it("loads a server the user connected from the card into this same turn, and tells the agent it is ready", async () => {
2140
2118
  const relay = recordingRelay();
2141
- const requests = [];
2142
- relay.credentialInputRequest = (_target, request) => {
2143
- requests.push(request);
2144
- return Promise.resolve(true);
2145
- };
2119
+ relay.connectionInputRequest = () => Promise.resolve(true);
2120
+ const controls = activeControls();
2121
+ const acme = { type: "http", url: "https://acme.dev/mcp" };
2122
+ const asks = [];
2123
+ const loaded = [];
2146
2124
  let decision;
2147
2125
  const executor = new BridgeJobExecutor({
2148
2126
  sdk: {
2149
2127
  query: (input) => ({
2150
2128
  async *[Symbol.asyncIterator]() {
2151
- decision = await input.options.canUseTool?.(CREDENTIAL_INPUT_TOOL_NAME, {
2152
- label: "Shopify admin token",
2153
- reason: "so I can update the theme",
2154
- allowedHosts: ["acme.myshopify.com"],
2155
- }, {
2156
- toolUseID: "t1",
2157
- requestId: "req_t1",
2158
- signal: input.options.abortController?.signal ?? new AbortController().signal,
2159
- });
2160
- yield resultMessage(0, "session_credential_off");
2129
+ const asked = input.options.canUseTool?.(CONNECTION_INPUT_TOOL_NAME, { connections: [{ server: { name: "acme", url: "https://acme.dev/mcp", auth: "none" }, reason: "r" }] }, { toolUseID: "t1", requestId: "req_t1", signal: new AbortController().signal });
2130
+ await new Promise((resolve) => setTimeout(resolve, 10));
2131
+ for (const [, pending] of controls.pendingConnectionInputs) {
2132
+ pending.resolve({ results: [{ status: "connected", server: "acme", scope: "company" }] });
2133
+ }
2134
+ decision = await asked;
2135
+ yield resultMessage(0, "session_after_connect");
2136
+ },
2137
+ setMcpServers: (servers) => {
2138
+ loaded.push(servers);
2139
+ return Promise.resolve({ added: ["acme"], removed: [], errors: {} });
2161
2140
  },
2162
2141
  }),
2163
2142
  },
2164
2143
  model: "claude-test",
2165
2144
  sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
2166
2145
  relay,
2146
+ mcpServersProvider: (_threadId, _actor, options) => {
2147
+ asks.push(options ?? {});
2148
+ const servers = options?.fresh ? { acme } : {};
2149
+ return Promise.resolve(servers);
2150
+ },
2167
2151
  });
2168
- await executor.execute({ threadId: "thread_co", turnId: "turn_co", prompt: "Fix my theme" }, activeControls());
2169
- expect(requests).toEqual([]);
2170
- expect(decision).toMatchObject({ behavior: "deny", message: expect.stringContaining("not available") });
2152
+ await executor.execute({ threadId: "thread_mcp", turnId: "turn_mcp", prompt: "Connect Acme" }, controls);
2153
+ expect(asks).toEqual([{}, { fresh: true }]);
2154
+ expect(Object.keys(loaded[0] ?? {}).sort()).toEqual(["acme", "baker_ui"]);
2155
+ expect(decision).toMatchObject({ behavior: "allow", updatedInput: { resolution: { toolsReady: true } } });
2171
2156
  });
2172
- it("parks a credential request and hands the agent only the placeholder the user's answer stored", async () => {
2173
- vi.stubEnv("BAKER_CREDENTIALS", "1");
2157
+ it("names a server that would not start, so the agent does not promise it for the next message", async () => {
2174
2158
  const relay = recordingRelay();
2175
- const requests = [];
2176
- relay.credentialInputRequest = (_target, request) => {
2177
- requests.push(request);
2178
- return Promise.resolve(true);
2179
- };
2159
+ relay.connectionInputRequest = () => Promise.resolve(true);
2180
2160
  const controls = activeControls();
2181
2161
  let decision;
2182
2162
  const executor = new BridgeJobExecutor({
2183
2163
  sdk: {
2184
2164
  query: (input) => ({
2185
2165
  async *[Symbol.asyncIterator]() {
2186
- const asked = input.options.canUseTool?.(CREDENTIAL_INPUT_TOOL_NAME, {
2187
- label: "Shopify admin token",
2188
- reason: "so I can update the theme",
2189
- allowedHosts: ["acme.myshopify.com"],
2190
- }, {
2191
- toolUseID: "t1",
2192
- requestId: "req_t1",
2193
- signal: input.options.abortController?.signal ?? new AbortController().signal,
2194
- });
2166
+ const asked = input.options.canUseTool?.(CONNECTION_INPUT_TOOL_NAME, { connections: [{ server: { name: "acme", url: "https://acme.dev/mcp" }, reason: "r" }] }, { toolUseID: "t1", requestId: "req_t1", signal: new AbortController().signal });
2195
2167
  await new Promise((resolve) => setTimeout(resolve, 10));
2196
- for (const [, pending] of controls.pendingCredentialInputs) {
2197
- pending.resolve({
2198
- status: "stored",
2199
- name: "shopify-admin-token",
2200
- placeholder: "{{credential:shopify-admin-token}}",
2201
- allowedHosts: ["acme.myshopify.com"],
2202
- });
2168
+ for (const [, pending] of controls.pendingConnectionInputs) {
2169
+ pending.resolve({ results: [{ status: "connected", server: "acme", scope: "company" }] });
2203
2170
  }
2204
2171
  decision = await asked;
2205
- yield resultMessage(0, "session_credential");
2172
+ yield resultMessage(0, "session_after_failed_load");
2206
2173
  },
2174
+ setMcpServers: () => Promise.resolve({ added: [], removed: [], errors: { acme: "401 Unauthorized" } }),
2207
2175
  }),
2208
2176
  },
2209
2177
  model: "claude-test",
2210
2178
  sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
2211
2179
  relay,
2180
+ mcpServersProvider: () => Promise.resolve({ acme: { type: "http", url: "https://acme.dev/mcp" } }),
2212
2181
  });
2213
- await executor.execute({ threadId: "thread_cr", turnId: "turn_cr", prompt: "Fix my theme" }, controls);
2214
- expect(requests).toEqual([
2215
- {
2216
- toolUseId: "t1",
2217
- label: "Shopify admin token",
2218
- reason: "so I can update the theme",
2219
- allowedHosts: ["acme.myshopify.com"],
2182
+ await executor.execute({ threadId: "thread_bad", turnId: "turn_bad", prompt: "Connect Acme" }, controls);
2183
+ expect(decision).toMatchObject({
2184
+ updatedInput: { resolution: { toolsReady: false, failedToLoad: ["acme"] } },
2185
+ });
2186
+ });
2187
+ it("does not call an app ready when the reloaded tools do not include it", async () => {
2188
+ const relay = recordingRelay();
2189
+ relay.connectionInputRequest = () => Promise.resolve(true);
2190
+ const controls = activeControls();
2191
+ let decision;
2192
+ const executor = new BridgeJobExecutor({
2193
+ sdk: {
2194
+ query: (input) => ({
2195
+ async *[Symbol.asyncIterator]() {
2196
+ const asked = input.options.canUseTool?.(CONNECTION_INPUT_TOOL_NAME, { connections: [{ app: "notion", reason: "r" }] }, { toolUseID: "t1", requestId: "req_t1", signal: new AbortController().signal });
2197
+ await new Promise((resolve) => setTimeout(resolve, 10));
2198
+ for (const [, pending] of controls.pendingConnectionInputs) {
2199
+ pending.resolve({ results: [{ status: "connected", app: "notion", scope: "company" }] });
2200
+ }
2201
+ decision = await asked;
2202
+ yield resultMessage(0, "session_after_missing_app");
2203
+ },
2204
+ setMcpServers: () => Promise.resolve({ added: [], removed: [], errors: {} }),
2205
+ }),
2220
2206
  },
2221
- ]);
2207
+ model: "claude-test",
2208
+ sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
2209
+ relay,
2210
+ mcpServersProvider: () => Promise.resolve({}),
2211
+ });
2212
+ await executor.execute({ threadId: "thread_app", turnId: "turn_app", prompt: "Connect Notion" }, controls);
2222
2213
  expect(decision).toMatchObject({
2223
- behavior: "allow",
2224
- updatedInput: { resolution: { status: "stored", placeholder: "{{credential:shopify-admin-token}}" } },
2214
+ updatedInput: { resolution: { toolsReady: false, failedToLoad: ["notion"] } },
2215
+ });
2216
+ });
2217
+ it("leaves the turn's tools alone when only a platform was connected", async () => {
2218
+ const relay = recordingRelay();
2219
+ relay.connectionInputRequest = () => Promise.resolve(true);
2220
+ const controls = activeControls();
2221
+ let reloads = 0;
2222
+ const executor = new BridgeJobExecutor({
2223
+ sdk: {
2224
+ query: (input) => ({
2225
+ async *[Symbol.asyncIterator]() {
2226
+ const asked = input.options.canUseTool?.(CONNECTION_INPUT_TOOL_NAME, { connections: [{ platform: "hubspot", reason: "r" }] }, { toolUseID: "t1", requestId: "req_t1", signal: new AbortController().signal });
2227
+ await new Promise((resolve) => setTimeout(resolve, 10));
2228
+ for (const [, pending] of controls.pendingConnectionInputs) {
2229
+ pending.resolve({ results: [{ status: "connected", platform: "hubspot", selected: [] }] });
2230
+ }
2231
+ await asked;
2232
+ yield resultMessage(0, "session_after_platform");
2233
+ },
2234
+ setMcpServers: () => {
2235
+ reloads += 1;
2236
+ return Promise.resolve({ added: [], removed: [], errors: {} });
2237
+ },
2238
+ }),
2239
+ },
2240
+ model: "claude-test",
2241
+ sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
2242
+ relay,
2225
2243
  });
2244
+ await executor.execute({ threadId: "thread_pl", turnId: "turn_pl", prompt: "Connect HubSpot" }, controls);
2245
+ expect(reloads).toBe(0);
2226
2246
  });
2227
2247
  it("refuses to ask for an avatar's face in a tool that renders only text", async () => {
2228
2248
  // Shipped three times, in both modes, after the agent had just read the doc saying
@@ -3636,9 +3656,7 @@ describe("BridgeJobExecutor review mode", () => {
3636
3656
  const options = queryInputs[0]?.options;
3637
3657
  expect(options.model).toBe("claude-session-model");
3638
3658
  expect(options.outputFormat).toBeUndefined();
3639
- // Only the credential scrub, which every turn runs; none of the review's hooks.
3640
- expect(Object.keys(options.hooks ?? {})).toEqual(["PostToolUse"]);
3641
- expect(options.hooks?.PostToolUse).toHaveLength(1);
3659
+ expect(options.hooks).toBeUndefined();
3642
3660
  expect(options.env?.MAX_STRUCTURED_OUTPUT_RETRIES).toBeUndefined();
3643
3661
  expect(options.disallowedTools).not.toContain("Write");
3644
3662
  expect(options.env?.BAKER_DEBUG_LOG).toBeUndefined();