@koda-sl/baker-bridge 0.118.0-dev.4a0a40cc5 → 0.118.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.
- package/README.md +17 -0
- package/dist/broker/baker-api.d.ts +23 -0
- package/dist/broker/baker-api.d.ts.map +1 -0
- package/dist/broker/baker-api.js +55 -0
- package/dist/broker/baker-api.js.map +1 -0
- package/dist/broker/broker-client.d.ts +10 -0
- package/dist/broker/broker-client.d.ts.map +1 -0
- package/dist/broker/broker-client.js +60 -0
- package/dist/broker/broker-client.js.map +1 -0
- package/dist/broker/ca.d.ts +38 -0
- package/dist/broker/ca.d.ts.map +1 -0
- package/dist/broker/ca.js +80 -0
- package/dist/broker/ca.js.map +1 -0
- package/dist/broker/ca.test.d.ts +2 -0
- package/dist/broker/ca.test.d.ts.map +1 -0
- package/dist/broker/ca.test.js +58 -0
- package/dist/broker/ca.test.js.map +1 -0
- package/dist/broker/credential-cache.d.ts +24 -0
- package/dist/broker/credential-cache.d.ts.map +1 -0
- package/dist/broker/credential-cache.js +69 -0
- package/dist/broker/credential-cache.js.map +1 -0
- package/dist/broker/credential-cache.test.d.ts +2 -0
- package/dist/broker/credential-cache.test.d.ts.map +1 -0
- package/dist/broker/credential-cache.test.js +120 -0
- package/dist/broker/credential-cache.test.js.map +1 -0
- package/dist/broker/credential-text.d.ts +45 -0
- package/dist/broker/credential-text.d.ts.map +1 -0
- package/dist/broker/credential-text.js +103 -0
- package/dist/broker/credential-text.js.map +1 -0
- package/dist/broker/credential-text.test.d.ts +2 -0
- package/dist/broker/credential-text.test.d.ts.map +1 -0
- package/dist/broker/credential-text.test.js +54 -0
- package/dist/broker/credential-text.test.js.map +1 -0
- package/dist/broker/env.d.ts +19 -0
- package/dist/broker/env.d.ts.map +1 -0
- package/dist/broker/env.js +16 -0
- package/dist/broker/env.js.map +1 -0
- package/dist/broker/main.d.ts +3 -0
- package/dist/broker/main.d.ts.map +1 -0
- package/dist/broker/main.js +51 -0
- package/dist/broker/main.js.map +1 -0
- package/dist/broker/proxy.d.ts +24 -0
- package/dist/broker/proxy.d.ts.map +1 -0
- package/dist/broker/proxy.integration.test.d.ts +2 -0
- package/dist/broker/proxy.integration.test.d.ts.map +1 -0
- package/dist/broker/proxy.integration.test.js +201 -0
- package/dist/broker/proxy.integration.test.js.map +1 -0
- package/dist/broker/proxy.js +147 -0
- package/dist/broker/proxy.js.map +1 -0
- package/dist/broker/rewrite.d.ts +44 -0
- package/dist/broker/rewrite.d.ts.map +1 -0
- package/dist/broker/rewrite.js +291 -0
- package/dist/broker/rewrite.js.map +1 -0
- package/dist/broker/rewrite.test.d.ts +2 -0
- package/dist/broker/rewrite.test.d.ts.map +1 -0
- package/dist/broker/rewrite.test.js +171 -0
- package/dist/broker/rewrite.test.js.map +1 -0
- package/dist/broker/socket-service.d.ts +18 -0
- package/dist/broker/socket-service.d.ts.map +1 -0
- package/dist/broker/socket-service.js +103 -0
- package/dist/broker/socket-service.js.map +1 -0
- package/dist/broker/socket-service.test.d.ts +2 -0
- package/dist/broker/socket-service.test.d.ts.map +1 -0
- package/dist/broker/socket-service.test.js +73 -0
- package/dist/broker/socket-service.test.js.map +1 -0
- package/dist/broker/token-bucket.d.ts +9 -0
- package/dist/broker/token-bucket.d.ts.map +1 -0
- package/dist/broker/token-bucket.js +18 -0
- package/dist/broker/token-bucket.js.map +1 -0
- package/dist/broker/usage-reporter.d.ts +18 -0
- package/dist/broker/usage-reporter.d.ts.map +1 -0
- package/dist/broker/usage-reporter.js +31 -0
- package/dist/broker/usage-reporter.js.map +1 -0
- package/dist/broker/usage-reporter.test.d.ts +2 -0
- package/dist/broker/usage-reporter.test.d.ts.map +1 -0
- package/dist/broker/usage-reporter.test.js +20 -0
- package/dist/broker/usage-reporter.test.js.map +1 -0
- package/dist/hono/agent-session.d.ts +3 -0
- package/dist/hono/agent-session.d.ts.map +1 -1
- package/dist/hono/agent-session.js +15 -0
- package/dist/hono/agent-session.js.map +1 -1
- package/dist/hono/agent.d.ts +2 -0
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +10 -2
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/avatar-casting.d.ts.map +1 -1
- package/dist/hono/avatar-casting.js +3 -2
- package/dist/hono/avatar-casting.js.map +1 -1
- package/dist/hono/baker-ui-tool-schemas.test.js +30 -4
- package/dist/hono/baker-ui-tool-schemas.test.js.map +1 -1
- package/dist/hono/blocking-card.d.ts +12 -0
- package/dist/hono/blocking-card.d.ts.map +1 -0
- package/dist/hono/blocking-card.js +12 -0
- package/dist/hono/blocking-card.js.map +1 -0
- package/dist/hono/bridge-job.d.ts +15 -2
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +80 -10
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +143 -1
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/connection-input.d.ts +15 -1
- package/dist/hono/connection-input.d.ts.map +1 -1
- package/dist/hono/connection-input.js +24 -5
- package/dist/hono/connection-input.js.map +1 -1
- package/dist/hono/connection-input.test.js +17 -8
- package/dist/hono/connection-input.test.js.map +1 -1
- package/dist/hono/convex.d.ts +8 -0
- package/dist/hono/convex.d.ts.map +1 -1
- package/dist/hono/convex.js +8 -0
- package/dist/hono/convex.js.map +1 -1
- package/dist/hono/credential-input.d.ts +39 -0
- package/dist/hono/credential-input.d.ts.map +1 -0
- package/dist/hono/credential-input.js +78 -0
- package/dist/hono/credential-input.js.map +1 -0
- package/dist/hono/credential-scrub.d.ts +41 -0
- package/dist/hono/credential-scrub.d.ts.map +1 -0
- package/dist/hono/credential-scrub.js +152 -0
- package/dist/hono/credential-scrub.js.map +1 -0
- package/dist/hono/credential-scrub.test.d.ts +2 -0
- package/dist/hono/credential-scrub.test.d.ts.map +1 -0
- package/dist/hono/credential-scrub.test.js +105 -0
- package/dist/hono/credential-scrub.test.js.map +1 -0
- package/dist/hono/flow-input.d.ts.map +1 -1
- package/dist/hono/flow-input.js +3 -2
- package/dist/hono/flow-input.js.map +1 -1
- package/dist/hono/prompt-context.d.ts +8 -1
- package/dist/hono/prompt-context.d.ts.map +1 -1
- package/dist/hono/prompt-context.js +45 -7
- package/dist/hono/prompt-context.js.map +1 -1
- package/dist/hono/prompt-context.test.js +35 -1
- package/dist/hono/prompt-context.test.js.map +1 -1
- package/dist/hono/relay.d.ts +10 -1
- package/dist/hono/relay.d.ts.map +1 -1
- package/dist/hono/relay.js +6 -0
- package/dist/hono/relay.js.map +1 -1
- package/dist/hono/server.d.ts.map +1 -1
- package/dist/hono/server.js +22 -0
- package/dist/hono/server.js.map +1 -1
- package/dist/hono/tag-input.d.ts +122 -3
- package/dist/hono/tag-input.d.ts.map +1 -1
- package/dist/hono/tag-input.js +27 -17
- package/dist/hono/tag-input.js.map +1 -1
- package/dist/hono/tag-input.test.js +19 -1
- package/dist/hono/tag-input.test.js.map +1 -1
- package/dist/hono/types.d.ts +8 -0
- package/dist/hono/types.d.ts.map +1 -1
- package/package.json +5 -2
|
@@ -18,6 +18,7 @@ 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";
|
|
21
22
|
import { FLOW_INPUT_TOOL_NAME } from "./flow-input.js";
|
|
22
23
|
import { bridgeRuntimeFiles } from "./runtime-files.js";
|
|
23
24
|
import { TAG_INPUT_TOOL_NAME } from "./tag-input.js";
|
|
@@ -49,6 +50,7 @@ function activeControls() {
|
|
|
49
50
|
pendingTagInputs: new Map(),
|
|
50
51
|
pendingFlowInputs: new Map(),
|
|
51
52
|
pendingConnectionInputs: new Map(),
|
|
53
|
+
pendingCredentialInputs: new Map(),
|
|
52
54
|
pendingVoiceCasts: new Map(),
|
|
53
55
|
pendingAvatarCastings: new Map(),
|
|
54
56
|
isActive: () => active,
|
|
@@ -82,6 +84,8 @@ function recordingRelay() {
|
|
|
82
84
|
flowInputResolved: () => Promise.resolve(),
|
|
83
85
|
connectionInputRequest: () => Promise.resolve(true),
|
|
84
86
|
connectionInputResolved: () => Promise.resolve(),
|
|
87
|
+
credentialInputRequest: () => Promise.resolve(true),
|
|
88
|
+
credentialInputResolved: () => Promise.resolve(),
|
|
85
89
|
avatarCastingRequest: () => Promise.resolve(true),
|
|
86
90
|
avatarCastingResolved: () => Promise.resolve(),
|
|
87
91
|
assistantEvent: (target, event, model) => {
|
|
@@ -1443,6 +1447,24 @@ describe("BridgeJobExecutor", () => {
|
|
|
1443
1447
|
expect(queryInputs[0]?.prompt).toBe("make the headline bigger");
|
|
1444
1448
|
expect(queryInputs[0]?.reminder).toContain('landing "Homepage" (slug: homepage)');
|
|
1445
1449
|
});
|
|
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
|
+
});
|
|
1446
1468
|
it("strips newlines from the viewing reference so a crafted title can't inject instructions", async () => {
|
|
1447
1469
|
const queryInputs = [];
|
|
1448
1470
|
const executor = createExecutor({
|
|
@@ -2184,6 +2206,36 @@ describe("BridgeJobExecutor", () => {
|
|
|
2184
2206
|
updatedInput: { resolution: { toolsReady: false, failedToLoad: ["acme"] } },
|
|
2185
2207
|
});
|
|
2186
2208
|
});
|
|
2209
|
+
it("does not call an app ready when the reloaded tools do not include it", async () => {
|
|
2210
|
+
const relay = recordingRelay();
|
|
2211
|
+
relay.connectionInputRequest = () => Promise.resolve(true);
|
|
2212
|
+
const controls = activeControls();
|
|
2213
|
+
let decision;
|
|
2214
|
+
const executor = new BridgeJobExecutor({
|
|
2215
|
+
sdk: {
|
|
2216
|
+
query: (input) => ({
|
|
2217
|
+
async *[Symbol.asyncIterator]() {
|
|
2218
|
+
const asked = input.options.canUseTool?.(CONNECTION_INPUT_TOOL_NAME, { connections: [{ app: "notion", reason: "r" }] }, { toolUseID: "t1", requestId: "req_t1", signal: new AbortController().signal });
|
|
2219
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2220
|
+
for (const [, pending] of controls.pendingConnectionInputs) {
|
|
2221
|
+
pending.resolve({ results: [{ status: "connected", app: "notion", scope: "company" }] });
|
|
2222
|
+
}
|
|
2223
|
+
decision = await asked;
|
|
2224
|
+
yield resultMessage(0, "session_after_missing_app");
|
|
2225
|
+
},
|
|
2226
|
+
setMcpServers: () => Promise.resolve({ added: [], removed: [], errors: {} }),
|
|
2227
|
+
}),
|
|
2228
|
+
},
|
|
2229
|
+
model: "claude-test",
|
|
2230
|
+
sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
|
|
2231
|
+
relay,
|
|
2232
|
+
mcpServersProvider: () => Promise.resolve({}),
|
|
2233
|
+
});
|
|
2234
|
+
await executor.execute({ threadId: "thread_app", turnId: "turn_app", prompt: "Connect Notion" }, controls);
|
|
2235
|
+
expect(decision).toMatchObject({
|
|
2236
|
+
updatedInput: { resolution: { toolsReady: false, failedToLoad: ["notion"] } },
|
|
2237
|
+
});
|
|
2238
|
+
});
|
|
2187
2239
|
it("leaves the turn's tools alone when only a platform was connected", async () => {
|
|
2188
2240
|
const relay = recordingRelay();
|
|
2189
2241
|
relay.connectionInputRequest = () => Promise.resolve(true);
|
|
@@ -2214,6 +2266,94 @@ describe("BridgeJobExecutor", () => {
|
|
|
2214
2266
|
await executor.execute({ threadId: "thread_pl", turnId: "turn_pl", prompt: "Connect HubSpot" }, controls);
|
|
2215
2267
|
expect(reloads).toBe(0);
|
|
2216
2268
|
});
|
|
2269
|
+
it("turns request_credential away in a Runtime without Credentials", async () => {
|
|
2270
|
+
const relay = recordingRelay();
|
|
2271
|
+
const requests = [];
|
|
2272
|
+
relay.credentialInputRequest = (_target, request) => {
|
|
2273
|
+
requests.push(request);
|
|
2274
|
+
return Promise.resolve(true);
|
|
2275
|
+
};
|
|
2276
|
+
let decision;
|
|
2277
|
+
const executor = new BridgeJobExecutor({
|
|
2278
|
+
sdk: {
|
|
2279
|
+
query: (input) => ({
|
|
2280
|
+
async *[Symbol.asyncIterator]() {
|
|
2281
|
+
decision = await input.options.canUseTool?.(CREDENTIAL_INPUT_TOOL_NAME, {
|
|
2282
|
+
label: "Shopify admin token",
|
|
2283
|
+
reason: "so I can update the theme",
|
|
2284
|
+
allowedHosts: ["acme.myshopify.com"],
|
|
2285
|
+
}, {
|
|
2286
|
+
toolUseID: "t1",
|
|
2287
|
+
requestId: "req_t1",
|
|
2288
|
+
signal: input.options.abortController?.signal ?? new AbortController().signal,
|
|
2289
|
+
});
|
|
2290
|
+
yield resultMessage(0, "session_credential_off");
|
|
2291
|
+
},
|
|
2292
|
+
}),
|
|
2293
|
+
},
|
|
2294
|
+
model: "claude-test",
|
|
2295
|
+
sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
|
|
2296
|
+
relay,
|
|
2297
|
+
});
|
|
2298
|
+
await executor.execute({ threadId: "thread_co", turnId: "turn_co", prompt: "Fix my theme" }, activeControls());
|
|
2299
|
+
expect(requests).toEqual([]);
|
|
2300
|
+
expect(decision).toMatchObject({ behavior: "deny", message: expect.stringContaining("not available") });
|
|
2301
|
+
});
|
|
2302
|
+
it("parks a credential request and hands the agent only the placeholder the user's answer stored", async () => {
|
|
2303
|
+
vi.stubEnv("BAKER_CREDENTIALS", "1");
|
|
2304
|
+
const relay = recordingRelay();
|
|
2305
|
+
const requests = [];
|
|
2306
|
+
relay.credentialInputRequest = (_target, request) => {
|
|
2307
|
+
requests.push(request);
|
|
2308
|
+
return Promise.resolve(true);
|
|
2309
|
+
};
|
|
2310
|
+
const controls = activeControls();
|
|
2311
|
+
let decision;
|
|
2312
|
+
const executor = new BridgeJobExecutor({
|
|
2313
|
+
sdk: {
|
|
2314
|
+
query: (input) => ({
|
|
2315
|
+
async *[Symbol.asyncIterator]() {
|
|
2316
|
+
const asked = input.options.canUseTool?.(CREDENTIAL_INPUT_TOOL_NAME, {
|
|
2317
|
+
label: "Shopify admin token",
|
|
2318
|
+
reason: "so I can update the theme",
|
|
2319
|
+
allowedHosts: ["acme.myshopify.com"],
|
|
2320
|
+
}, {
|
|
2321
|
+
toolUseID: "t1",
|
|
2322
|
+
requestId: "req_t1",
|
|
2323
|
+
signal: input.options.abortController?.signal ?? new AbortController().signal,
|
|
2324
|
+
});
|
|
2325
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2326
|
+
for (const [, pending] of controls.pendingCredentialInputs) {
|
|
2327
|
+
pending.resolve({
|
|
2328
|
+
status: "stored",
|
|
2329
|
+
name: "shopify-admin-token",
|
|
2330
|
+
placeholder: "{{credential:shopify-admin-token}}",
|
|
2331
|
+
allowedHosts: ["acme.myshopify.com"],
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2334
|
+
decision = await asked;
|
|
2335
|
+
yield resultMessage(0, "session_credential");
|
|
2336
|
+
},
|
|
2337
|
+
}),
|
|
2338
|
+
},
|
|
2339
|
+
model: "claude-test",
|
|
2340
|
+
sessionStore: { load: async () => undefined, save: async () => undefined, clear: async () => undefined },
|
|
2341
|
+
relay,
|
|
2342
|
+
});
|
|
2343
|
+
await executor.execute({ threadId: "thread_cr", turnId: "turn_cr", prompt: "Fix my theme" }, controls);
|
|
2344
|
+
expect(requests).toEqual([
|
|
2345
|
+
{
|
|
2346
|
+
toolUseId: "t1",
|
|
2347
|
+
label: "Shopify admin token",
|
|
2348
|
+
reason: "so I can update the theme",
|
|
2349
|
+
allowedHosts: ["acme.myshopify.com"],
|
|
2350
|
+
},
|
|
2351
|
+
]);
|
|
2352
|
+
expect(decision).toMatchObject({
|
|
2353
|
+
behavior: "allow",
|
|
2354
|
+
updatedInput: { resolution: { status: "stored", placeholder: "{{credential:shopify-admin-token}}" } },
|
|
2355
|
+
});
|
|
2356
|
+
});
|
|
2217
2357
|
it("refuses to ask for an avatar's face in a tool that renders only text", async () => {
|
|
2218
2358
|
// Shipped three times, in both modes, after the agent had just read the doc saying
|
|
2219
2359
|
// not to: "Elige el rostro para Clara, tu presentadora de placas solares" with
|
|
@@ -3626,7 +3766,9 @@ describe("BridgeJobExecutor review mode", () => {
|
|
|
3626
3766
|
const options = queryInputs[0]?.options;
|
|
3627
3767
|
expect(options.model).toBe("claude-session-model");
|
|
3628
3768
|
expect(options.outputFormat).toBeUndefined();
|
|
3629
|
-
|
|
3769
|
+
// Only the credential scrub, which every turn runs; none of the review's hooks.
|
|
3770
|
+
expect(Object.keys(options.hooks ?? {})).toEqual(["PostToolUse"]);
|
|
3771
|
+
expect(options.hooks?.PostToolUse).toHaveLength(1);
|
|
3630
3772
|
expect(options.env?.MAX_STRUCTURED_OUTPUT_RETRIES).toBeUndefined();
|
|
3631
3773
|
expect(options.disallowedTools).not.toContain("Write");
|
|
3632
3774
|
expect(options.env?.BAKER_DEBUG_LOG).toBeUndefined();
|