@desplega.ai/agent-swarm 2.7.0 → 2.7.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.
- package/dist/{acp-adapter-ma1js5n7.js → acp-adapter-8dn5tq56.js} +6 -6
- package/dist/{actions-1vhmtvg9.js → actions-3r6gw7dy.js} +18 -18
- package/dist/{amp-adapter-sxqqvmdk.js → amp-adapter-wjtq413p.js} +3 -3
- package/dist/{anthropic-messages-txs190dd.js → anthropic-messages-n4cby1rz.js} +4 -4
- package/dist/{app-mwx1d5a9.js → app-d53yhykk.js} +3 -3
- package/dist/{assistant-yx1p6g82.js → assistant-ksrawj3k.js} +20 -20
- package/dist/{boot-reembed-7h78vmvv.js → boot-reembed-fxfw17m2.js} +10 -3
- package/dist/{boot-reembed-5h37a2c2.js → boot-reembed-k5y5xbj0.js} +15 -8
- package/dist/{boot-scrub-sweep-8mawd4gw.js → boot-scrub-sweep-se41j9fd.js} +3 -3
- package/dist/{boot-seeds-ca84dhnn.js → boot-seeds-r3kwwv8b.js} +4 -4
- package/dist/{claude-adapter-wqt4hfkq.js → claude-adapter-ahmyf231.js} +7 -7
- package/dist/{claude-managed-adapter-6fjqtr2z.js → claude-managed-adapter-5knamegc.js} +3 -3
- package/dist/{claude-managed-setup-rqv98sea.js → claude-managed-setup-mdc7dy6b.js} +2 -2
- package/dist/{claude-sdk-session-f29f3b2x.js → claude-sdk-session-n5wen9zk.js} +8728 -8599
- package/dist/{cli-m5e802r7.js → cli-0dqtv2jg.js} +2 -2
- package/dist/{cli-e1595bgx.js → cli-0tww7dnz.js} +2 -2
- package/dist/{cli-2y7v133v.js → cli-0w4e4v58.js} +7 -7
- package/dist/{cli-d20qvpr2.js → cli-2sjm3t4r.js} +1 -1
- package/dist/{cli-gf2850q7.js → cli-3cywb44q.js} +18 -1
- package/dist/{cli-8wkb09q5.js → cli-3k9jej0c.js} +2 -2
- package/dist/{cli-twctnkng.js → cli-3v2cyqb8.js} +3 -3
- package/dist/{cli-he9gbdx0.js → cli-5qt9vzmq.js} +39 -20
- package/dist/{cli-a6ds2epe.js → cli-5rp1w4cr.js} +1 -1
- package/dist/{cli-6srv653c.js → cli-6vwjsetx.js} +4 -4
- package/dist/{cli-1hhbzkbb.js → cli-6w2yrrc0.js} +8 -8
- package/dist/{cli-f12mr20z.js → cli-75tdydgv.js} +1 -1
- package/dist/{cli-j3y0x2n4.js → cli-8feswf2v.js} +43 -33
- package/dist/{cli-07q03xm2.js → cli-8wd3mbyj.js} +1 -1
- package/dist/{cli-ymjpkxgn.js → cli-9csfthbw.js} +8 -6
- package/dist/{cli-f1e0ptjj.js → cli-b41p764a.js} +21 -2
- package/dist/{cli-kv7sbc2c.js → cli-c1t533hh.js} +3 -3
- package/dist/{cli-54sj64fc.js → cli-c28jxpcv.js} +1 -1
- package/dist/{cli-8mbc9za9.js → cli-cb50g9cd.js} +1 -1
- package/dist/{cli-c668vvcf.js → cli-d8gaphtr.js} +1 -1
- package/dist/{cli-86ehn4s5.js → cli-dgtfysne.js} +2 -2
- package/dist/{cli-sjctjr48.js → cli-dscnhn18.js} +1 -1
- package/dist/{cli-j0ppywdr.js → cli-dv11pgpv.js} +12 -12
- package/dist/{cli-1m9x8dr5.js → cli-ekptgk2m.js} +5 -5
- package/dist/{cli-9gsm2rzp.js → cli-f3mzy662.js} +17 -17
- package/dist/{cli-s0mgx214.js → cli-fk7k8s9x.js} +2 -2
- package/dist/{cli-vbhgkw9h.js → cli-h3e7bhvn.js} +3 -3
- package/dist/{cli-yd2nreqw.js → cli-hkxqdmnb.js} +2 -2
- package/dist/{cli-8wmj18cz.js → cli-hpkvgdad.js} +7 -4
- package/dist/{cli-wqr7cea4.js → cli-hq2v4rr5.js} +37 -9
- package/dist/{cli-sgqm2582.js → cli-k1zb7raw.js} +5 -5
- package/dist/{cli-4rvr7zfx.js → cli-k4awgvzm.js} +5 -0
- package/dist/{cli-ay40dnj3.js → cli-k7d3hvya.js} +2 -2
- package/dist/{cli-j9bpmykh.js → cli-kbtdftbw.js} +5 -5
- package/dist/{cli-x37r7qwf.js → cli-kj69b9tw.js} +25 -5
- package/dist/{cli-gsfk58nw.js → cli-kk9jy4nm.js} +1 -1
- package/dist/{cli-39aet655.js → cli-m52t4cta.js} +1 -1
- package/dist/{cli-h5jeg46p.js → cli-mdadewqp.js} +5 -5
- package/dist/{cli-a89zdqz9.js → cli-nf6k60sn.js} +1 -1
- package/dist/{cli-v6shg7na.js → cli-nzdf09js.js} +1 -1
- package/dist/{cli-rr7zx19j.js → cli-prcyzecg.js} +12 -12
- package/dist/{cli-6a9qfa8b.js → cli-pzafyqtk.js} +118 -48
- package/dist/{cli-48gxjmcz.js → cli-qvaa1gjp.js} +87 -24
- package/dist/{cli-qj442fws.js → cli-rg4b2g6j.js} +1 -1
- package/dist/{cli-aypd09nf.js → cli-rm66vqdz.js} +1 -1
- package/dist/{cli-9pshx6rd.js → cli-s504c3w7.js} +1 -1
- package/dist/{cli-ptfq202x.js → cli-swkx9jm2.js} +3 -3
- package/dist/{cli-m30k9777.js → cli-thsaq4pd.js} +16 -16
- package/dist/{cli-60sty27p.js → cli-twjnyvs8.js} +2 -2
- package/dist/{cli-rd5m70gj.js → cli-typdpe8g.js} +4 -4
- package/dist/{cli-yxbsmx56.js → cli-vg8pwmsd.js} +6 -6
- package/dist/{cli-s09j9vp5.js → cli-vhpckzvp.js} +1 -1
- package/dist/{cli-dv97kdzv.js → cli-wdxgsdz5.js} +2 -2
- package/dist/{cli-7a6p4e65.js → cli-wtjg6je3.js} +1 -1
- package/dist/{cli-b3yzyc57.js → cli-x3cngb1h.js} +44 -12
- package/dist/{cli-6mgdba42.js → cli-xbz6mcg4.js} +2 -2
- package/dist/{cli-2pvzmas1.js → cli-y4tdxsqb.js} +3 -3
- package/dist/{cli-f4dbh7a5.js → cli-yqrsp3ny.js} +7 -7
- package/dist/cli.js +27 -19
- package/dist/{codex-adapter-zk59x2zh.js → codex-adapter-7wepzq15.js} +5 -5
- package/dist/{codex-hook-xyjhvxwd.js → codex-hook-pbdh4xhx.js} +2 -2
- package/dist/{codex-session-runner-kh6s4j3n.js → codex-session-runner-02sb49e4.js} +5 -5
- package/dist/{commands-68et1qv2.js → commands-3rcspxct.js} +2 -2
- package/dist/{controller-fyrbnzg4.js → controller-8ar4avd6.js} +3 -3
- package/dist/{controllers-connect-nep9h2xv.js → controllers-connect-ajvh9h0v.js} +19 -19
- package/dist/{cursor-adapter-yss3pg7t.js → cursor-adapter-gd0sa7bh.js} +1 -1
- package/dist/{db-28gjyvxj.js → db-dv9j7ts5.js} +2 -2
- package/dist/{db-8ftwvzba.js → db-z26vgdvj.js} +3 -3
- package/dist/{dispatcher-hayexmkr.js → dispatcher-8m0htjq8.js} +17 -17
- package/dist/{dsh-adapter-46wawff9.js → dsh-adapter-y8gyk130.js} +1 -1
- package/dist/{e2b-fn3zacvt.js → e2b-74vg9b7e.js} +1 -1
- package/dist/{e2b-222hsajc.js → e2b-jyay8wzn.js} +1 -1
- package/dist/{easter-egg-3d-8d1e0h4m.js → easter-egg-3d-28f880xx.js} +1 -1
- package/dist/{execute-cjrfxfnm.js → execute-9seb79vh.js} +1 -1
- package/dist/{external-channel-xbmxcg09.js → external-channel-smz7jyth.js} +2 -2
- package/dist/{getMachineId-bsd-brn0xym3.js → getMachineId-bsd-whfre6gr.js} +3 -3
- package/dist/{getMachineId-darwin-t339sfxm.js → getMachineId-darwin-5zjynb19.js} +3 -3
- package/dist/{getMachineId-linux-5eq95d8b.js → getMachineId-linux-8mksrrsq.js} +3 -3
- package/dist/{getMachineId-unsupported-qavrtc7j.js → getMachineId-unsupported-fxtqsdt2.js} +3 -3
- package/dist/{getMachineId-win-q7fe1wx7.js → getMachineId-win-nzfmz857.js} +3 -3
- package/dist/{grok-adapter-ag4wks2a.js → grok-adapter-z0nnvtbn.js} +7 -7
- package/dist/handlers-pspryh6g.js +41 -0
- package/dist/{heartbeat-psfvcgwp.js → heartbeat-f928aqyp.js} +20 -20
- package/dist/{hook-cyq4mryn.js → hook-d7c605r4.js} +7 -7
- package/dist/{hook-8pz04697.js → hook-q9hv5xf9.js} +5 -5
- package/dist/{http-haj1nd6k.js → http-q6j4k989.js} +934 -180
- package/dist/{index-z5h22pes.js → index-5nb266jr.js} +17 -17
- package/dist/{index-ysd45kgc.js → index-8fxt5eah.js} +10 -10
- package/dist/{index-zgvqzjsw.js → index-cekzwhez.js} +5 -5
- package/dist/{index-zyq8ct52.js → index-ch0c1xff.js} +17 -17
- package/dist/{index-syvhnvtw.js → index-ebnjhxh1.js} +1 -1
- package/dist/{index-y1ajx04a.js → index-ed8dy8rn.js} +20 -20
- package/dist/{index-jwt2bj6f.js → index-ejqdkkqx.js} +11 -10
- package/dist/{index-dr94zbnh.js → index-farm1zsn.js} +32661 -29443
- package/dist/{index-q52f47pe.js → index-yn1yxg85.js} +1 -1
- package/dist/{keepalive-xdvsamvj.js → keepalive-zzc3hks1.js} +3 -3
- package/dist/{lead-hqg57kdp.js → lead-c0pjcaw4.js} +36 -36
- package/dist/{maintenance-4y2xzh3a.js → maintenance-kqsxzpzx.js} +1 -1
- package/dist/{oauth-refresh-sweep-jd4r7zbs.js → oauth-refresh-sweep-7qt0g55z.js} +2 -2
- package/dist/{onboard-18447q9q.js → onboard-k7x13fqg.js} +118 -5
- package/dist/{opencode-adapter-26b2frdf.js → opencode-adapter-tqvrtter.js} +5 -5
- package/dist/{otel-impl-f9tgr8yw.js → otel-impl-sqkf6k3b.js} +97 -97
- package/dist/{pi-mono-adapter-qn6qbga1.js → pi-mono-adapter-m2qnafxm.js} +63 -9
- package/dist/{pricing-refresh-dw2tgb53.js → pricing-refresh-wkpwhgvs.js} +3 -3
- package/dist/{rbac-roles-s4nwj2m3.js → rbac-roles-dpn0c0wj.js} +7 -4
- package/dist/{rbac-roles-aygm2760.js → rbac-roles-wk7xd6a6.js} +2 -2
- package/dist/{render-v2-yfvdfr0x.js → render-v2-ex2m4g2k.js} +3 -3
- package/dist/{resume-1bmvjbf3.js → resume-725g9b0b.js} +7 -7
- package/dist/{runtime-f7tpzedy.js → runtime-kajas15g.js} +1 -1
- package/dist/{session-access-r5garej6.js → session-access-0j2ezjje.js} +8 -4
- package/dist/{session-source-backfill-424wzv0r.js → session-source-backfill-62202awe.js} +2 -2
- package/dist/{setup-8tygvxkq.js → setup-9sj11ax6.js} +1 -1
- package/dist/{virtual-modules-xsw323b3.js → virtual-modules-c6fcq6zr.js} +2 -2
- package/dist/{work-objects-ggnghpgf.js → work-objects-0y07495y.js} +20 -20
- package/dist/{worker-sqjd1nqf.js → worker-d4q9sqbc.js} +36 -36
- package/openapi.json +1070 -9
- package/package.json +3 -3
- package/src/be/connector-codes.ts +65 -22
- package/src/be/memory/boot-reembed.ts +4 -1
- package/src/be/memory/constants.ts +6 -0
- package/src/be/memory/embedding-recovery.ts +48 -0
- package/src/be/memory/index-content.ts +5 -2
- package/src/be/memory/providers/openai-embedding.ts +65 -14
- package/src/be/memory/task-learning.ts +110 -8
- package/src/be/memory/types.ts +13 -2
- package/src/be/migrations/246_connector_code_kind.sql +11 -0
- package/src/be/onboarding.ts +125 -15
- package/src/be/rbac-roles.ts +4 -1
- package/src/be/scripts/embeddings.ts +2 -2
- package/src/be/seed/agent-fs-provision.ts +75 -14
- package/src/be/swarm-config-guard.ts +3 -0
- package/src/cli.tsx +9 -0
- package/src/comb/config.ts +6 -1
- package/src/commands/onboard/agent-fs-version.ts +5 -0
- package/src/commands/onboard/compose-generator.ts +112 -1
- package/src/commands/onboard/env-generator.ts +9 -0
- package/src/commands/onboard/tei-image.ts +12 -0
- package/src/commands/onboard/types.ts +7 -0
- package/src/commands/onboard.tsx +11 -1
- package/src/commands/runner.ts +14 -1
- package/src/http/agentfs-proxy.ts +369 -0
- package/src/http/all-routes.ts +1 -0
- package/src/http/codex-oauth-device.ts +8 -1
- package/src/http/fs.ts +64 -10
- package/src/http/inbox-state.ts +27 -1
- package/src/http/index.ts +4 -1
- package/src/http/memory.ts +7 -4
- package/src/http/onboarding.ts +139 -11
- package/src/http/session-access.ts +24 -0
- package/src/http/sessions.ts +10 -6
- package/src/http/tasks.ts +85 -11
- package/src/http/telemetry-ui.ts +1 -1
- package/src/http/user-roles.ts +4 -1
- package/src/http/users.ts +272 -3
- package/src/http/utils.ts +22 -3
- package/src/prompts/base-prompt.ts +24 -9
- package/src/prompts/session-templates.ts +26 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +6 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +58 -3
- package/src/rbac/legacy-policy.ts +1 -0
- package/src/rbac/permissions.ts +4 -0
- package/src/tests/agent-fs-provision-seeder.test.ts +261 -92
- package/src/tests/agentfs-proxy.test.ts +1106 -0
- package/src/tests/base-prompt.test.ts +69 -2
- package/src/tests/codex-adapter.test.ts +46 -8
- package/src/tests/codex-oauth-device.test.ts +12 -1
- package/src/tests/comb-config-guard.test.ts +20 -0
- package/src/tests/comb-links.test.ts +79 -1
- package/src/tests/comb-status.test.ts +44 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/fixtures/onboard/baseline-states.ts +68 -0
- package/src/tests/fixtures/onboard/content.compose.yml.txt +190 -0
- package/src/tests/fixtures/onboard/content.env.txt +29 -0
- package/src/tests/fixtures/onboard/dev.compose.yml.txt +155 -0
- package/src/tests/fixtures/onboard/dev.env.txt +28 -0
- package/src/tests/fixtures/onboard/full-all.compose.yml.txt +582 -0
- package/src/tests/fixtures/onboard/full-all.env.txt +59 -0
- package/src/tests/fixtures/onboard/full.compose.yml.txt +435 -0
- package/src/tests/fixtures/onboard/full.env.txt +36 -0
- package/src/tests/fixtures/onboard/research.compose.yml.txt +155 -0
- package/src/tests/fixtures/onboard/research.env.txt +28 -0
- package/src/tests/fixtures/onboard/solo.compose.yml.txt +85 -0
- package/src/tests/fixtures/onboard/solo.env.txt +26 -0
- package/src/tests/http-log-scrubbing.test.ts +34 -1
- package/src/tests/http-task-write-ownership.test.ts +5 -1
- package/src/tests/invites-http.test.ts +464 -0
- package/src/tests/memory-embedding-input-cap.test.ts +122 -1
- package/src/tests/memory-embedding-recovery.test.ts +137 -0
- package/src/tests/onboard-compose.test.ts +142 -0
- package/src/tests/onboard-env.test.ts +24 -0
- package/src/tests/onboard-non-interactive.test.ts +29 -0
- package/src/tests/onboard-tei-image.test.ts +36 -0
- package/src/tests/onboarding.test.ts +451 -4
- package/src/tests/openai-embedding-provider.test.ts +105 -2
- package/src/tests/pi-mono-session-cost-on-abort.test.ts +270 -0
- package/src/tests/preload-env.test.ts +4 -0
- package/src/tests/preload.ts +4 -0
- package/src/tests/prompt-template-session.test.ts +19 -3
- package/src/tests/rbac-admission-e2e.test.ts +22 -6
- package/src/tests/rbac-admission.test.ts +342 -4
- package/src/tests/rbac-engine.test.ts +1 -0
- package/src/tests/rbac-roles.test.ts +9 -1
- package/src/tests/send-task-requester-gate.test.ts +64 -3
- package/src/tests/sessions-move.test.ts +39 -1
- package/src/tests/store-progress-learning.test.ts +95 -2
- package/src/tests/whoami-route.test.ts +41 -0
- package/src/tools/inject-learning.ts +1 -1
- package/src/tools/memory-edit.ts +1 -1
- package/src/tools/memory-search.ts +1 -1
- package/src/tools/store-progress.ts +5 -1
- package/src/tools/utils.ts +12 -1
- package/src/utils/constants.ts +39 -0
- package/src/utils/task-attachment-links.ts +15 -3
- package/templates/skills/swarm-docs/content.md +1 -1
- package/dist/handlers-tzmevqb5.js +0 -41
- package/dist/{azure-openai-responses-9kfwhmn7.js → azure-openai-responses-43asa23s.js} +0 -0
- package/dist/{node-vxx896fa.js → node-t28cc56b.js} +0 -0
- package/dist/{openai-codex-responses-79s8xnbh.js → openai-codex-responses-jhr3sjtm.js} +3 -3
- package/dist/{openai-completions-tdbyts0x.js → openai-completions-gs6yn37k.js} +3 -3
- /package/dist/{openai-responses-dm3t5vqp.js → openai-responses-jqm9vwwk.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, type Mock, spyOn, test } from "bun:test";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import type { ZodType } from "zod";
|
|
4
4
|
import {
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
initDb,
|
|
11
11
|
startTask,
|
|
12
12
|
} from "../be/db";
|
|
13
|
+
import { getEmbeddingProvider, getMemoryStore } from "../be/memory";
|
|
14
|
+
import { EMBEDDING_DIMENSIONS } from "../be/memory/constants";
|
|
13
15
|
import { registerStoreProgressTool } from "../tools/store-progress";
|
|
14
16
|
|
|
15
17
|
interface ToolResult {
|
|
@@ -73,7 +75,7 @@ function learningRows(taskId: string): MemoryRow[] {
|
|
|
73
75
|
|
|
74
76
|
function learningData(result: ToolResult) {
|
|
75
77
|
return result.structuredContent?.learning as
|
|
76
|
-
| { status: string; key?: string; error?: string }
|
|
78
|
+
| { status: string; key?: string; memoryId?: string; similarity?: number; error?: string }
|
|
77
79
|
| undefined;
|
|
78
80
|
}
|
|
79
81
|
|
|
@@ -286,3 +288,94 @@ describe("store-progress learning", () => {
|
|
|
286
288
|
expect(learningRows(t.id)).toHaveLength(0);
|
|
287
289
|
});
|
|
288
290
|
});
|
|
291
|
+
|
|
292
|
+
describe("store-progress learning near-duplicate guard", () => {
|
|
293
|
+
const vectors = new Map<string, Float32Array>();
|
|
294
|
+
let embedSpy: Mock<(text: string) => Promise<Float32Array | null>>;
|
|
295
|
+
|
|
296
|
+
/** Unit vector on `axis`, tilted toward `axis + 1` so its cosine to the bare axis is `cos`. */
|
|
297
|
+
function vector(axis: number, cos = 1): Float32Array {
|
|
298
|
+
const v = new Float32Array(EMBEDDING_DIMENSIONS);
|
|
299
|
+
v[axis] = cos;
|
|
300
|
+
v[axis + 1] = Math.sqrt(1 - cos ** 2);
|
|
301
|
+
return v;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Store a learning and give it its embedding now, not in the background. */
|
|
305
|
+
async function seed(text: string, embedding: Float32Array, workstream = "seeded") {
|
|
306
|
+
vectors.set(text, embedding);
|
|
307
|
+
const t = await task();
|
|
308
|
+
const result = await call({ taskId: t.id, learning: { text, workstream } });
|
|
309
|
+
const memoryId = learningData(result)!.memoryId!;
|
|
310
|
+
await getMemoryStore().updateEmbedding(memoryId, embedding, "test-embedding");
|
|
311
|
+
return { task: t, memoryId, key: learningData(result)!.key! };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
beforeAll(() => {
|
|
315
|
+
embedSpy = spyOn(getEmbeddingProvider(), "embed").mockImplementation(
|
|
316
|
+
async (text: string) => vectors.get(text) ?? null,
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
afterAll(() => embedSpy.mockRestore());
|
|
320
|
+
|
|
321
|
+
test("a near duplicate in another workstream is not stored and rates the existing row", async () => {
|
|
322
|
+
const existing = await seed("Upsert scripts from file bytes\nPOST the raw file.", vector(10));
|
|
323
|
+
const text = "Byte-exact script upsert from a local file\nPOST it to the API.";
|
|
324
|
+
vectors.set(text, vector(10, 0.9));
|
|
325
|
+
const t = await task();
|
|
326
|
+
const result = await call({ taskId: t.id, learning: { text, workstream: "other" } });
|
|
327
|
+
|
|
328
|
+
expect(learningData(result)).toMatchObject({
|
|
329
|
+
status: "duplicate",
|
|
330
|
+
memoryId: existing.memoryId,
|
|
331
|
+
key: existing.key,
|
|
332
|
+
});
|
|
333
|
+
expect(learningData(result)?.similarity).toBeCloseTo(0.9, 2);
|
|
334
|
+
expect(message(result)).toContain(`Learning not stored: it matches ${existing.key}`);
|
|
335
|
+
expect(String(result.structuredContent?.nudge)).toContain(`memory-edit that memory instead`);
|
|
336
|
+
expect(String(result.structuredContent?.nudge)).toContain(existing.memoryId);
|
|
337
|
+
expect(learningRows(t.id)).toHaveLength(0);
|
|
338
|
+
const ratings = getDb()
|
|
339
|
+
.query<{ source: string; signal: number; taskId: string }, [string]>(
|
|
340
|
+
"SELECT source, signal, taskId FROM memory_rating WHERE memoryId = ?",
|
|
341
|
+
)
|
|
342
|
+
.all(existing.memoryId);
|
|
343
|
+
expect(ratings).toEqual([{ source: "learning-duplicate", signal: 1, taskId: t.id }]);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("a related learning below the threshold is stored", async () => {
|
|
347
|
+
await seed("Retry flaky pushes once\nThe pre-push hook is slow.", vector(20));
|
|
348
|
+
const text = "Pre-push hooks take five minutes\nLet them finish.";
|
|
349
|
+
vectors.set(text, vector(20, 0.7));
|
|
350
|
+
const t = await task();
|
|
351
|
+
const result = await call({ taskId: t.id, learning: text });
|
|
352
|
+
|
|
353
|
+
expect(learningData(result)?.status).toBe("stored");
|
|
354
|
+
expect(learningRows(t.id)).toHaveLength(1);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("a failed search falls through to the normal insert", async () => {
|
|
358
|
+
await seed("Kebab keys only\nSlugs are lowercase.", vector(30));
|
|
359
|
+
const text = "Keys are kebab case\nSlugs stay lowercase.";
|
|
360
|
+
vectors.set(text, vector(30, 0.95));
|
|
361
|
+
const searchSpy = spyOn(getMemoryStore(), "search").mockRejectedValue(new Error("vec down"));
|
|
362
|
+
try {
|
|
363
|
+
const t = await task();
|
|
364
|
+
const result = await call({ taskId: t.id, progress: "kept", learning: text });
|
|
365
|
+
expect(learningData(result)?.status).toBe("stored");
|
|
366
|
+
expect(learningRows(t.id)).toHaveLength(1);
|
|
367
|
+
expect((await getTaskById(t.id))?.progress).toBe("kept");
|
|
368
|
+
} finally {
|
|
369
|
+
searchSpy.mockRestore();
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test("an exact replay on the same task is replayed, not a duplicate", async () => {
|
|
374
|
+
const text = "Replay before similarity\nThe same task retrying is not a duplicate.";
|
|
375
|
+
const seeded = await seed(text, vector(40));
|
|
376
|
+
const replay = await call({ taskId: seeded.task.id, learning: { text, workstream: "seeded" } });
|
|
377
|
+
|
|
378
|
+
expect(learningData(replay)).toMatchObject({ status: "replayed", memoryId: seeded.memoryId });
|
|
379
|
+
expect(learningRows(seeded.task.id)).toHaveLength(1);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type ServerResponse,
|
|
18
18
|
} from "node:http";
|
|
19
19
|
import { closeDb, createUser, initDb, updateUser } from "../be/db";
|
|
20
|
+
import { ensureRbacSeedsSynced, setUserRoles } from "../be/rbac-roles";
|
|
20
21
|
import { type IdentityActor, mintToken, revokeToken } from "../be/users";
|
|
21
22
|
import { handleCore } from "../http/core";
|
|
22
23
|
import { handleUsers } from "../http/users";
|
|
@@ -30,6 +31,7 @@ const ACTOR: IdentityActor = { kind: "operator", id: "op:test" };
|
|
|
30
31
|
interface WhoamiBody {
|
|
31
32
|
kind: "operator" | "user";
|
|
32
33
|
user: { id: string; name: string; status: string } | null;
|
|
34
|
+
grants?: { grantsAll: boolean; verbs: string[]; roles: string[] };
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
function createTestServer(): Server {
|
|
@@ -61,6 +63,7 @@ describe("GET /api/whoami", () => {
|
|
|
61
63
|
beforeAll(async () => {
|
|
62
64
|
cleanupDb();
|
|
63
65
|
initDb(TEST_DB_PATH);
|
|
66
|
+
ensureRbacSeedsSynced({ quiet: true });
|
|
64
67
|
server = createTestServer();
|
|
65
68
|
port = await listenOnFreePort(server);
|
|
66
69
|
});
|
|
@@ -82,6 +85,7 @@ describe("GET /api/whoami", () => {
|
|
|
82
85
|
const body = (await res.json()) as WhoamiBody;
|
|
83
86
|
expect(body.kind).toBe("operator");
|
|
84
87
|
expect(body.user).toBeNull();
|
|
88
|
+
expect(body.grants?.grantsAll).toBe(true);
|
|
85
89
|
});
|
|
86
90
|
|
|
87
91
|
test("active user token resolves to its bound user", async () => {
|
|
@@ -96,6 +100,43 @@ describe("GET /api/whoami", () => {
|
|
|
96
100
|
expect(body.user?.name).toBe("Whoami User");
|
|
97
101
|
});
|
|
98
102
|
|
|
103
|
+
test("requester token reports its role and verbs, without grantsAll", async () => {
|
|
104
|
+
const user = await createUser({ name: "Requester User", email: "req@example.com" });
|
|
105
|
+
await setUserRoles(user.id, ["requester"], null);
|
|
106
|
+
const { plaintext } = await mintToken(user.id, "rest", ACTOR);
|
|
107
|
+
|
|
108
|
+
const body = (await (await whoami(plaintext)).json()) as WhoamiBody;
|
|
109
|
+
expect(body.grants?.grantsAll).toBe(false);
|
|
110
|
+
expect(body.grants?.roles).toEqual(["requester"]);
|
|
111
|
+
expect(body.grants?.verbs).toContain("task.create.own");
|
|
112
|
+
expect(body.grants?.verbs).not.toContain("config.write.any");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("a new user holds admin by default: grantsAll", async () => {
|
|
116
|
+
const user = await createUser({ name: "Default Admin" });
|
|
117
|
+
const { plaintext } = await mintToken(user.id, "rest", ACTOR);
|
|
118
|
+
|
|
119
|
+
const body = (await (await whoami(plaintext)).json()) as WhoamiBody;
|
|
120
|
+
expect(body.grants?.grantsAll).toBe(true);
|
|
121
|
+
expect(body.grants?.roles).toEqual(["admin"]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("RBAC_ENABLED=false reports grantsAll for a viewer", async () => {
|
|
125
|
+
const user = await createUser({ name: "Viewer User" });
|
|
126
|
+
await setUserRoles(user.id, ["viewer"], null);
|
|
127
|
+
const { plaintext } = await mintToken(user.id, "rest", ACTOR);
|
|
128
|
+
const previous = process.env.RBAC_ENABLED;
|
|
129
|
+
process.env.RBAC_ENABLED = "false";
|
|
130
|
+
try {
|
|
131
|
+
const body = (await (await whoami(plaintext)).json()) as WhoamiBody;
|
|
132
|
+
expect(body.grants?.grantsAll).toBe(true);
|
|
133
|
+
expect(body.grants?.roles).toEqual(["viewer"]);
|
|
134
|
+
} finally {
|
|
135
|
+
if (previous === undefined) delete process.env.RBAC_ENABLED;
|
|
136
|
+
else process.env.RBAC_ENABLED = previous;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
99
140
|
test("revoked token is rejected at auth (401)", async () => {
|
|
100
141
|
const user = await createUser({ name: "Revoked User" });
|
|
101
142
|
const { plaintext, tokenId } = await mintToken(user.id, "rest", ACTOR);
|
|
@@ -73,7 +73,7 @@ export const registerInjectLearningTool = (server: McpServer) => {
|
|
|
73
73
|
// Generate and store embedding (async, best-effort)
|
|
74
74
|
try {
|
|
75
75
|
const provider = getEmbeddingProvider();
|
|
76
|
-
const embedding = await provider.embed(memory.content);
|
|
76
|
+
const embedding = await provider.embed(memory.content, { kind: "document" });
|
|
77
77
|
if (embedding) {
|
|
78
78
|
await store.updateEmbedding(memory.id, embedding, provider.name);
|
|
79
79
|
}
|
package/src/tools/memory-edit.ts
CHANGED
|
@@ -183,7 +183,7 @@ export const registerMemoryEditTool = (server: McpServer) => {
|
|
|
183
183
|
content !== undefined || oldString !== undefined || newString !== undefined;
|
|
184
184
|
if (result.changed && (newKey === undefined || contentEdited)) {
|
|
185
185
|
const provider = getEmbeddingProvider();
|
|
186
|
-
const embedding = await provider.embed(result.memory.content);
|
|
186
|
+
const embedding = await provider.embed(result.memory.content, { kind: "document" });
|
|
187
187
|
if (embedding) await store.updateEmbedding(result.memory.id, embedding, provider.name);
|
|
188
188
|
try {
|
|
189
189
|
// Edit path: prune links derived from removed content (sequel links survive).
|
|
@@ -120,7 +120,7 @@ export const registerMemorySearchTool = (server: McpServer) => {
|
|
|
120
120
|
// Try vector search first
|
|
121
121
|
const provider = getEmbeddingProvider();
|
|
122
122
|
const store = getMemoryStore();
|
|
123
|
-
const queryEmbedding = await provider.embed(query);
|
|
123
|
+
const queryEmbedding = await provider.embed(query, { kind: "query" });
|
|
124
124
|
|
|
125
125
|
const candidateLimit = limit * CANDIDATE_SET_MULTIPLIER;
|
|
126
126
|
const candidates = await searchMemoryCandidates(
|
|
@@ -125,17 +125,21 @@ export const storeProgressOutputSchema = swarmToolOutputSchema({
|
|
|
125
125
|
key: z.string().optional(),
|
|
126
126
|
memoryId: z.string().optional(),
|
|
127
127
|
workstream: z.string().optional(),
|
|
128
|
+
similarity: z.number().optional(),
|
|
128
129
|
error: z.string().optional(),
|
|
129
130
|
})
|
|
130
131
|
.optional()
|
|
131
132
|
.describe(
|
|
132
|
-
"Present when the call carried a learning: stored, replayed (same text already stored for this task), or failed with error.",
|
|
133
|
+
"Present when the call carried a learning: stored, replayed (same text already stored for this task), duplicate (an existing swarm memory at key/memoryId says the same; similarity is the raw cosine), or failed with error.",
|
|
133
134
|
),
|
|
134
135
|
});
|
|
135
136
|
|
|
136
137
|
function learningSentence(result: TaskLearningResult): string {
|
|
137
138
|
if (result.status === "stored") return `Learning stored at ${result.key}.`;
|
|
138
139
|
if (result.status === "replayed") return `Learning already stored at ${result.key}; skipped.`;
|
|
140
|
+
if (result.status === "duplicate") {
|
|
141
|
+
return `Learning not stored: it matches ${result.key} (similarity ${result.similarity}).`;
|
|
142
|
+
}
|
|
139
143
|
return `Learning not stored: ${result.error}.`;
|
|
140
144
|
}
|
|
141
145
|
|
package/src/tools/utils.ts
CHANGED
|
@@ -297,6 +297,17 @@ const storeProgressBlockedWaitingNudge = (r: SwarmToolResult): string | undefine
|
|
|
297
297
|
return `That reads as blocked-waiting, ${formatIdleDuration(ms)} since your last update — keep working if you can, and if the wait is genuinely long, defer-task is one way to resume later instead of polling.`;
|
|
298
298
|
};
|
|
299
299
|
|
|
300
|
+
const storeProgressNudge = (r: SwarmToolResult): string | undefined => {
|
|
301
|
+
const learning = (r.data as { learning?: { status?: unknown; memoryId?: unknown } } | undefined)
|
|
302
|
+
?.learning;
|
|
303
|
+
// nudgeMiddleware permits exactly one steer: the duplicate-learning steer
|
|
304
|
+
// names a concrete next call, so it wins over the blocked-waiting reminder.
|
|
305
|
+
if (r.ok && learning?.status === "duplicate" && typeof learning.memoryId === "string") {
|
|
306
|
+
return `That learning repeats memory ${learning.memoryId}; if your text adds something, memory-edit that memory instead of storing a new one.`;
|
|
307
|
+
}
|
|
308
|
+
return storeProgressBlockedWaitingNudge(r);
|
|
309
|
+
};
|
|
310
|
+
|
|
300
311
|
const workflowLongScriptTimeoutNudge = (r: SwarmToolResult): string | undefined => {
|
|
301
312
|
if (!r.ok) return undefined;
|
|
302
313
|
const hint = (r.data as { longScriptTimeoutHint?: unknown } | undefined)?.longScriptTimeoutHint;
|
|
@@ -311,7 +322,7 @@ const workflowLongScriptTimeoutNudge = (r: SwarmToolResult): string | undefined
|
|
|
311
322
|
export const NUDGES: Record<string, (result: SwarmToolResult) => string | undefined> = {
|
|
312
323
|
"defer-task": (r) =>
|
|
313
324
|
r.ok ? "Stop working on this task now; the wake-up task will carry your note." : undefined,
|
|
314
|
-
"store-progress":
|
|
325
|
+
"store-progress": storeProgressNudge,
|
|
315
326
|
"script-run": scriptRunNudge,
|
|
316
327
|
"script-upsert": scriptAuthoringNudge,
|
|
317
328
|
"launch-script-run": scriptAuthoringNudge,
|
package/src/utils/constants.ts
CHANGED
|
@@ -89,6 +89,36 @@ export function getAgentFsLiveUrl(): string {
|
|
|
89
89
|
return (raw || DEFAULT_AGENT_FS_LIVE_URL).replace(/\/+$/, "");
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/** Where people-facing agent-fs file links point: Comb in the dashboard, or the live app. */
|
|
93
|
+
export type AgentFsLinkTarget = "dashboard" | "live";
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The operator's `AGENT_FS_LINK_TARGET` choice (trimmed, lowercased). Null when
|
|
97
|
+
* unset, blank, or invalid: every surface then keeps its automatic behavior.
|
|
98
|
+
*/
|
|
99
|
+
export function readAgentFsLinkTarget(): AgentFsLinkTarget | null {
|
|
100
|
+
const raw = process.env.AGENT_FS_LINK_TARGET?.trim().toLowerCase();
|
|
101
|
+
return raw === "dashboard" || raw === "live" ? raw : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The base URL (no trailing slash) that a people-facing file link starts with,
|
|
106
|
+
* per {@link readAgentFsLinkTarget}. `dashboard` uses `APP_URL` when one is
|
|
107
|
+
* configured (and, for attachments, Comb is on), else the live app. Null when
|
|
108
|
+
* no target is set: the caller keeps its current code path.
|
|
109
|
+
*
|
|
110
|
+
* The prompt surface skips the Comb check: workers do not get `COMB_ENABLED`,
|
|
111
|
+
* and an explicit `dashboard` is the operator's choice.
|
|
112
|
+
*/
|
|
113
|
+
export function resolveAgentFsLinkBase(surface: "prompt" | "attachment"): string | null {
|
|
114
|
+
const target = readAgentFsLinkTarget();
|
|
115
|
+
if (target === null) return null;
|
|
116
|
+
if (target === "dashboard" && getConfiguredAppUrls().length > 0) {
|
|
117
|
+
if (surface === "prompt" || isCombEnabled()) return getAppUrl();
|
|
118
|
+
}
|
|
119
|
+
return getAgentFsLiveUrl();
|
|
120
|
+
}
|
|
121
|
+
|
|
92
122
|
/**
|
|
93
123
|
* Optional fallback agent-fs `org_id` for attachments that store only `path`.
|
|
94
124
|
* Strictly opt-in — when neither env var is set, the renderer keeps the
|
|
@@ -166,6 +196,15 @@ export function isCombEnabled(): boolean {
|
|
|
166
196
|
return isEnvFlagEnabled("COMB_ENABLED", false) && Boolean(apiUrl);
|
|
167
197
|
}
|
|
168
198
|
|
|
199
|
+
/**
|
|
200
|
+
* `AGENT_FS_PROXY`: the API serves agent-fs at `/agentfs/*` (plus the public
|
|
201
|
+
* `/share/*` and `/site/*` pages), and Comb uses `<public API URL>/agentfs`.
|
|
202
|
+
* Read per request, so a config upsert applies without a restart. Off by default.
|
|
203
|
+
*/
|
|
204
|
+
export function isAgentFsProxyEnabled(): boolean {
|
|
205
|
+
return isEnvFlagEnabled("AGENT_FS_PROXY", false);
|
|
206
|
+
}
|
|
207
|
+
|
|
169
208
|
/**
|
|
170
209
|
* The dashboard (Comb) URL for an agent-fs file, same id and encoding rules as
|
|
171
210
|
* {@link buildAgentFsLiveUrl}. Null unless Comb is on AND an explicit
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { TaskAttachment } from "../types";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
agentFsFileRoute,
|
|
4
|
+
buildAgentFsLiveUrl,
|
|
5
|
+
buildCombFileUrl,
|
|
6
|
+
getAppUrl,
|
|
7
|
+
resolveAgentFsLinkBase,
|
|
8
|
+
} from "./constants";
|
|
3
9
|
|
|
4
10
|
function shellQuote(value: string): string {
|
|
5
11
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -26,8 +32,9 @@ export function taskAttachmentFetchCommand(
|
|
|
26
32
|
/**
|
|
27
33
|
* The link a human (Slack, prompts, citations) sees for an attachment. An
|
|
28
34
|
* agent-fs file links to the dashboard (Comb) when Comb is on and `APP_URL` is
|
|
29
|
-
* set, else to the agent-fs live UI, else to the raw `agent-fs:<path>`.
|
|
30
|
-
*
|
|
35
|
+
* set, else to the agent-fs live UI, else to the raw `agent-fs:<path>`. An
|
|
36
|
+
* explicit `AGENT_FS_LINK_TARGET` picks the base instead (see
|
|
37
|
+
* `resolveAgentFsLinkBase`). `comb: false` always links to the live UI.
|
|
31
38
|
*/
|
|
32
39
|
export function taskAttachmentDisplayUrl(
|
|
33
40
|
attachment: TaskAttachment,
|
|
@@ -40,6 +47,11 @@ export function taskAttachmentDisplayUrl(
|
|
|
40
47
|
|
|
41
48
|
if (attachment.providerId === "agent-fs" || attachment.kind === "agent-fs") {
|
|
42
49
|
const file = { path: attachment.path, orgId: attachment.orgId, driveId: attachment.driveId };
|
|
50
|
+
const linkBase = opts.comb === false ? null : resolveAgentFsLinkBase("attachment");
|
|
51
|
+
if (linkBase !== null) {
|
|
52
|
+
const route = agentFsFileRoute(file);
|
|
53
|
+
return route ? `${linkBase}/file/~/${route}` : `agent-fs:${attachment.path ?? ""}`;
|
|
54
|
+
}
|
|
43
55
|
const combUrl = opts.comb === false ? null : buildCombFileUrl(file);
|
|
44
56
|
return combUrl ?? buildAgentFsLiveUrl(file) ?? `agent-fs:${attachment.path ?? ""}`;
|
|
45
57
|
}
|
|
@@ -118,7 +118,7 @@ Fetch the page as markdown: `curl -fsSL https://docs.agent-swarm.dev/llms.mdx/do
|
|
|
118
118
|
- [Overview](https://docs.agent-swarm.dev/docs/ui)
|
|
119
119
|
- [Sessions](https://docs.agent-swarm.dev/docs/ui/sessions)
|
|
120
120
|
- [Configuration](https://docs.agent-swarm.dev/docs/ui/configuration)
|
|
121
|
-
- [Comb
|
|
121
|
+
- [Comb](https://docs.agent-swarm.dev/docs/ui/comb)
|
|
122
122
|
- [Integrations](https://docs.agent-swarm.dev/docs/integrations)
|
|
123
123
|
- [Slack Integration](https://docs.agent-swarm.dev/docs/integrations/slack)
|
|
124
124
|
- [GitHub App Integration](https://docs.agent-swarm.dev/docs/integrations/github)
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isUserAllowed2,
|
|
3
|
-
registerMessageHandler2
|
|
4
|
-
} from "./cli-f4dbh7a5.js";
|
|
5
|
-
import"./cli-sgqm2582.js";
|
|
6
|
-
import"./cli-2pvzmas1.js";
|
|
7
|
-
import"./cli-6a9qfa8b.js";
|
|
8
|
-
import"./cli-737pyqxr.js";
|
|
9
|
-
import"./cli-8mbc9za9.js";
|
|
10
|
-
import"./cli-qz93y3x5.js";
|
|
11
|
-
import"./cli-3h26v7yj.js";
|
|
12
|
-
import"./cli-60sty27p.js";
|
|
13
|
-
import"./cli-j9bpmykh.js";
|
|
14
|
-
import"./cli-3ggwdtb0.js";
|
|
15
|
-
import"./cli-aypd09nf.js";
|
|
16
|
-
import"./cli-rd5m70gj.js";
|
|
17
|
-
import"./cli-d20qvpr2.js";
|
|
18
|
-
import"./cli-g9ypd5en.js";
|
|
19
|
-
import"./cli-twctnkng.js";
|
|
20
|
-
import"./cli-j0ppywdr.js";
|
|
21
|
-
import"./cli-1m9x8dr5.js";
|
|
22
|
-
import"./cli-0z1xjzwa.js";
|
|
23
|
-
import"./cli-e8xyjvfc.js";
|
|
24
|
-
import"./cli-wqr7cea4.js";
|
|
25
|
-
import"./cli-13p25grh.js";
|
|
26
|
-
import"./cli-0adyhvq2.js";
|
|
27
|
-
import"./cli-m30k9777.js";
|
|
28
|
-
import"./cli-s09j9vp5.js";
|
|
29
|
-
import"./cli-6srv653c.js";
|
|
30
|
-
import"./cli-a89zdqz9.js";
|
|
31
|
-
import"./cli-rycdaj0a.js";
|
|
32
|
-
import"./cli-445c1vp7.js";
|
|
33
|
-
import"./cli-kvzgak7c.js";
|
|
34
|
-
import"./cli-2nf3b08t.js";
|
|
35
|
-
import"./cli-8wmj18cz.js";
|
|
36
|
-
import"./cli-48gxjmcz.js";
|
|
37
|
-
import"./cli-kt907da6.js";
|
|
38
|
-
export {
|
|
39
|
-
isUserAllowed2 as isUserAllowed,
|
|
40
|
-
registerMessageHandler2 as registerMessageHandler
|
|
41
|
-
};
|
|
File without changes
|
|
File without changes
|
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
} from "./cli-2nf3b08t.js";
|
|
10
10
|
import"./cli-445c1vp7.js";
|
|
11
11
|
import"./cli-kvzgak7c.js";
|
|
12
|
+
import {
|
|
13
|
+
combineAbortSignals
|
|
14
|
+
} from "./cli-aphet7e8.js";
|
|
12
15
|
import {
|
|
13
16
|
getResponsesToolSupport,
|
|
14
17
|
convertResponsesMessages,
|
|
@@ -18,9 +21,6 @@ import {
|
|
|
18
21
|
import {
|
|
19
22
|
clampOpenAIPromptCacheKey
|
|
20
23
|
} from "./cli-dxqypk0n.js";
|
|
21
|
-
import {
|
|
22
|
-
combineAbortSignals
|
|
23
|
-
} from "./cli-aphet7e8.js";
|
|
24
24
|
import {
|
|
25
25
|
registerSessionResourceCleanup,
|
|
26
26
|
uuidv7
|
|
@@ -24,12 +24,12 @@ import {
|
|
|
24
24
|
import {
|
|
25
25
|
clampOpenAIPromptCacheKey
|
|
26
26
|
} from "./cli-dxqypk0n.js";
|
|
27
|
-
import {
|
|
28
|
-
retryProviderRequest
|
|
29
|
-
} from "./cli-w6pm0v4s.js";
|
|
30
27
|
import {
|
|
31
28
|
shortHash
|
|
32
29
|
} from "./cli-j3xf15kq.js";
|
|
30
|
+
import {
|
|
31
|
+
retryProviderRequest
|
|
32
|
+
} from "./cli-w6pm0v4s.js";
|
|
33
33
|
import {
|
|
34
34
|
normalizeProviderError,
|
|
35
35
|
formatProviderError
|
|
File without changes
|