@desplega.ai/agent-swarm 2.4.0 → 2.4.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/README.md +1 -1
- package/dist/{acp-adapter-kedstxx6.js → acp-adapter-zvzr538d.js} +9 -9
- package/dist/{actions-vget6r1k.js → actions-jhtqdw69.js} +21 -21
- package/dist/{amp-adapter-xeb5mktv.js → amp-adapter-bd84rhs2.js} +4 -4
- package/dist/{app-mqap8t8m.js → app-kreq1gwg.js} +3 -3
- package/dist/{assistant-h0gv97mv.js → assistant-3k22sbsq.js} +22 -22
- package/dist/{boot-reembed-qr8a894z.js → boot-reembed-e53x6b9v.js} +1 -1
- package/dist/{boot-reembed-rj85jjhw.js → boot-reembed-f6z923ny.js} +1 -1
- package/dist/{boot-scrub-sweep-eyfvn6v9.js → boot-scrub-sweep-0538vsb7.js} +4 -4
- package/dist/{boot-seeds-xs9a8dx1.js → boot-seeds-6wxqkfk2.js} +4 -4
- package/dist/{claude-adapter-bm23cye7.js → claude-adapter-gfts5044.js} +9 -9
- package/dist/{claude-managed-adapter-1mwrsm9d.js → claude-managed-adapter-h2y889ge.js} +2 -2
- package/dist/{claude-managed-setup-gkfgks4j.js → claude-managed-setup-h00hsgtz.js} +2 -2
- package/dist/{claude-sdk-session-apb4ypz3.js → claude-sdk-session-56besmfz.js} +13 -13
- package/dist/{cli-nrrg0fvy.js → cli-0bh477zn.js} +18 -5
- package/dist/{cli-7gh7020n.js → cli-1dmcq2eh.js} +1 -1
- package/dist/{cli-7ayprxp7.js → cli-2dfbv8qr.js} +8 -0
- package/dist/{cli-1cevz46c.js → cli-3kh4kpqy.js} +6 -6
- package/dist/{cli-tg9ksbn8.js → cli-3p8fqcnh.js} +2 -2
- package/dist/{cli-x1p5dhq2.js → cli-3r448dqn.js} +3 -3
- package/dist/{cli-ecshf504.js → cli-3tnpj2bh.js} +7 -7
- package/dist/{cli-ffbrkh1r.js → cli-471qk6s2.js} +46 -38
- package/dist/{cli-a49vpbf3.js → cli-5kqnemen.js} +1 -1
- package/dist/{cli-zvze9rbm.js → cli-6ncjvx55.js} +3 -3
- package/dist/{cli-fb6t92v8.js → cli-6x9ma5w5.js} +1 -1
- package/dist/{cli-c8fwpgqb.js → cli-7225gwj7.js} +2 -2
- package/dist/{cli-bn26xbcs.js → cli-8nyhf7za.js} +1 -1
- package/dist/{cli-y83zk5sb.js → cli-a0kcty51.js} +4 -4
- package/dist/{cli-8b9wvjps.js → cli-a4gvwttf.js} +4 -4
- package/dist/{cli-jhp7w1fy.js → cli-a5ebc95n.js} +2 -2
- package/dist/{cli-mz1ezzzh.js → cli-ash6xxk7.js} +2 -2
- package/dist/{cli-rsd7ga7v.js → cli-axh29tyr.js} +11 -11
- package/dist/{cli-p22zdvnt.js → cli-bn0rewsy.js} +3 -3
- package/dist/{cli-6ftrrwm1.js → cli-bn5kevnf.js} +5 -5
- package/dist/{cli-p1m2b6gc.js → cli-d2mb5s8a.js} +7 -7
- package/dist/{cli-c5sbmw1v.js → cli-d82btycs.js} +94 -15
- package/dist/{cli-vjfpshn3.js → cli-ejs3m1sx.js} +1 -1
- package/dist/{cli-a1esmmee.js → cli-fpmsqq59.js} +7 -2
- package/dist/{cli-8cxkw1f5.js → cli-fz9kewbh.js} +2 -2
- package/dist/{cli-8rwvksbc.js → cli-g0hgtz4p.js} +5 -5
- package/dist/{cli-kz116kvw.js → cli-gf0kfg81.js} +7 -7
- package/dist/{cli-eqgfs202.js → cli-hqhzg1qq.js} +2 -2
- package/dist/{cli-3wjs22x3.js → cli-j4rqdf2n.js} +2 -2
- package/dist/{cli-ywyrffff.js → cli-jh0qcrga.js} +1 -1
- package/dist/{cli-ttaz6c7m.js → cli-k9z4zd4p.js} +6 -5
- package/dist/{cli-nme7wery.js → cli-kmqgmcnb.js} +46 -13
- package/dist/{cli-x719j3vs.js → cli-kr2pmfqx.js} +392 -168
- package/dist/{cli-wrv09v7q.js → cli-m2qgh5sv.js} +1 -1
- package/dist/{cli-xfe63zx3.js → cli-mfe7f7b5.js} +2 -2
- package/dist/{cli-x3en6ct3.js → cli-nwyw3zhg.js} +1 -1
- package/dist/{cli-5s5hx57y.js → cli-nx462e4v.js} +1 -1
- package/dist/{cli-bfc3k1x5.js → cli-p0rakbrk.js} +9 -9
- package/dist/{cli-avmqhatn.js → cli-p6argxh9.js} +8 -8
- package/dist/{cli-3avfh5az.js → cli-pemywhfq.js} +2 -2
- package/dist/{cli-sppc0cmw.js → cli-pnp2j5zg.js} +2 -2
- package/dist/{cli-wk8ccrz6.js → cli-pw7v69vp.js} +2 -2
- package/dist/{cli-bhwa8rzc.js → cli-rdq7tzwm.js} +13 -12
- package/dist/{cli-rg7ntypm.js → cli-rqqsfz30.js} +379 -87
- package/dist/{cli-kk2r80n5.js → cli-s48yvzb8.js} +4 -4
- package/dist/{cli-zv4vy2b0.js → cli-s95dknxh.js} +1 -1
- package/dist/{cli-b80a1100.js → cli-sjyetj21.js} +2 -2
- package/dist/{cli-rdr166ht.js → cli-smvcw9z5.js} +1 -1
- package/dist/{cli-2rwet3r7.js → cli-sv5gb0yb.js} +1 -1
- package/dist/{cli-5ff2sjyt.js → cli-syhq378v.js} +2 -2
- package/dist/{cli-tj4j2ts4.js → cli-tbhwrxpt.js} +8 -8
- package/dist/{cli-4fhyq711.js → cli-vy0fay6k.js} +13 -13
- package/dist/{cli-ptkpaqfy.js → cli-wt645v7q.js} +1 -1
- package/dist/{cli-f3nx1h8z.js → cli-wxbn3yfx.js} +2 -2
- package/dist/{cli-wyrr38xm.js → cli-x5mq1fyq.js} +1 -1
- package/dist/{cli-ccn0eybf.js → cli-xbzvet96.js} +6 -6
- package/dist/{cli-4mkvwgzr.js → cli-xf234ws8.js} +1 -1
- package/dist/{cli-tgvpmnwz.js → cli-xftrvxag.js} +5 -5
- package/dist/{cli-02vhhssk.js → cli-z071fb95.js} +5 -5
- package/dist/{cli-mvg2hf8p.js → cli-z1ew8vbq.js} +14 -7
- package/dist/{cli-dsgj3e7a.js → cli-zfg9enh9.js} +2 -2
- package/dist/{cli-yxqag76b.js → cli-zw88zjba.js} +1 -1
- package/dist/cli.js +19 -19
- package/dist/{codex-adapter-pp2gq8gr.js → codex-adapter-p6rmm7vv.js} +6 -6
- package/dist/{codex-hook-qwzccd64.js → codex-hook-x7nejyrr.js} +7 -4
- package/dist/{codex-login-35p4sk85.js → codex-login-m819c41r.js} +1 -1
- package/dist/{codex-session-runner-0vzn09t8.js → codex-session-runner-8vd5t9t0.js} +7 -7
- package/dist/{commands-psqhkttb.js → commands-7ems2p13.js} +2 -2
- package/dist/{controller-t20vz2k8.js → controller-m263fg43.js} +4 -4
- package/dist/{controllers-connect-gkxmqw9d.js → controllers-connect-bg33ae53.js} +23 -23
- package/dist/{cursor-adapter-3v542qe5.js → cursor-adapter-cz6nm6mj.js} +3 -3
- package/dist/{db-2xbyenjr.js → db-w505dwa8.js} +2 -2
- package/dist/{db-nc1rd869.js → db-ys2rbdft.js} +3 -3
- package/dist/{devin-adapter-7egzmt0k.js → devin-adapter-zgqadvnm.js} +1 -1
- package/dist/{dispatcher-ewceb8ts.js → dispatcher-0s0mckqr.js} +20 -20
- package/dist/{docker-njavd3fb.js → docker-fkgtr75t.js} +2 -2
- package/dist/{dsh-adapter-75xwh78t.js → dsh-adapter-3n3net33.js} +3 -3
- package/dist/{e2b-5r6a5jeb.js → e2b-7am6tmq6.js} +2 -2
- package/dist/{e2b-pw1nvtmh.js → e2b-thdcxtjd.js} +2 -2
- package/dist/{easter-egg-3d-xsc47jwf.js → easter-egg-3d-5cgynaja.js} +1 -1
- package/dist/{event-bus-101fenkh.js → event-bus-9vpk8gmq.js} +1 -1
- package/dist/{execute-gzmw1mnw.js → execute-t4e6m3rw.js} +1 -1
- package/dist/{external-channel-a5dsmxn4.js → external-channel-5b23fv8z.js} +2 -2
- package/dist/{grok-adapter-vj88xr23.js → grok-adapter-q9fghe5q.js} +10 -10
- package/dist/handlers-mqrym347.js +39 -0
- package/dist/{heartbeat-t2m9r3wa.js → heartbeat-tww6yx1w.js} +23 -23
- package/dist/{hook-xa677f8r.js → hook-dx0pkvar.js} +16 -9
- package/dist/{hook-8femx1bg.js → hook-pvmh9b6m.js} +6 -6
- package/dist/{http-xpmmq028.js → http-k2ejbt05.js} +199 -131
- package/dist/{index-s7ckdajq.js → index-2z710v4x.js} +10 -10
- package/dist/{index-dg2tmj99.js → index-dgz61nff.js} +20 -20
- package/dist/{index-syztqdt6.js → index-g6tbb6ve.js} +1 -1
- package/dist/index-h2ek08d6.js +40 -0
- package/dist/index-pqfwh9nn.js +41 -0
- package/dist/{index-cdzyfrsp.js → index-x5aktmp8.js} +1 -1
- package/dist/{keepalive-3nr4st3r.js → keepalive-nhvpw10z.js} +4 -4
- package/dist/lead-jb6sf69z.js +78 -0
- package/dist/{maintenance-verwpe2c.js → maintenance-agakc519.js} +1 -1
- package/dist/{oauth-refresh-sweep-9q2t0y3q.js → oauth-refresh-sweep-4dcbhtn0.js} +3 -3
- package/dist/{onboard-aytqedmq.js → onboard-4n2kwa4v.js} +3 -3
- package/dist/{opencode-adapter-f4hryjny.js → opencode-adapter-3s7ax02e.js} +7 -7
- package/dist/{otel-impl-hckw4wt1.js → otel-impl-tfa12080.js} +2 -2
- package/dist/{pi-mono-adapter-hxby0ce1.js → pi-mono-adapter-ytp7gz8b.js} +22 -11
- package/dist/{pricing-refresh-5nvme3sm.js → pricing-refresh-3cqx3f3x.js} +3 -3
- package/dist/{rbac-roles-pd8c26m1.js → rbac-roles-9fae5rnv.js} +1 -1
- package/dist/{rbac-roles-vbpy21mg.js → rbac-roles-y6zbfzve.js} +2 -2
- package/dist/{render-v2-7nqgvk2q.js → render-v2-emawjvc4.js} +3 -3
- package/dist/{resume-b6djcj3c.js → resume-zhgts7h7.js} +10 -8
- package/dist/{runtime-txrxc9za.js → runtime-xe3aqy4x.js} +1 -1
- package/dist/{session-access-fc3f9y12.js → session-access-cm823e06.js} +4 -4
- package/dist/{setup-n39szm6b.js → setup-tkp99w1e.js} +1 -1
- package/dist/{virtual-modules-wyp2k6z3.js → virtual-modules-4r3zkc20.js} +2 -2
- package/dist/{work-objects-jem2fre0.js → work-objects-f722h263.js} +23 -23
- package/dist/worker-p7f336rq.js +78 -0
- package/dist/{x-8ewt8gxn.js → x-y45mthwn.js} +2 -2
- package/openapi.json +99 -52
- package/package.json +2 -2
- package/src/apps/action-runner.ts +146 -0
- package/src/apps/row-store.ts +4 -2
- package/src/apps/script-types.ts +1 -1
- package/src/be/db.ts +14 -4
- package/src/be/fleet-benchmark-stats.ts +10 -5
- package/src/be/models-catalog.ts +4 -0
- package/src/be/onboarding.ts +6 -0
- package/src/be/scripts/typecheck.ts +13 -0
- package/src/be/swarm-config-guard.ts +10 -1
- package/src/be/telemetry-enable.ts +1 -1
- package/src/commands/provider-credentials.ts +12 -2
- package/src/commands/runner.ts +3 -0
- package/src/heartbeat/heartbeat.ts +2 -2
- package/src/hooks/codex-hook.ts +6 -2
- package/src/hooks/hook.ts +7 -0
- package/src/hooks/pr-body-guard.ts +38 -11
- package/src/hooks/pr-room-guard.ts +88 -0
- package/src/http/agents.ts +1 -0
- package/src/http/apps.ts +84 -181
- package/src/http/fleet-benchmark.ts +79 -30
- package/src/http/global-config.ts +7 -0
- package/src/http/ranking.ts +24 -40
- package/src/http/tasks.ts +2 -1
- package/src/http/telemetry-ui.ts +1 -1
- package/src/http/used-by.ts +55 -19
- package/src/http/users.ts +2 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +15 -0
- package/src/providers/reasoning-effort.ts +2 -1
- package/src/providers/types.ts +2 -0
- package/src/ranking/telemetry-ranking.ts +5 -33
- package/src/scripts-runtime/sdk-allowlist.ts +7 -0
- package/src/scripts-runtime/types/stdlib.d.ts +31 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +31 -0
- package/src/server.ts +4 -0
- package/src/telemetry-context.ts +19 -1
- package/src/telemetry-contract/EVENTS.md +42 -8
- package/src/telemetry-contract/SOURCE.json +6 -5
- package/src/telemetry-contract/catalog.json +225 -5
- package/src/telemetry-contract/ranking/fixtures/valid/no-claim.json +10 -0
- package/src/telemetry-contract/ranking/listing.v1.schema.json +2 -2
- package/src/telemetry-contract/types.gen.ts +225 -27
- package/src/telemetry-identity.ts +47 -9
- package/src/telemetry-snapshot.ts +9 -1
- package/src/telemetry-ui-events.ts +9 -2
- package/src/telemetry.ts +14 -3
- package/src/tests/app-action-run-tool.test.ts +178 -0
- package/src/tests/app-row-tools.test.ts +360 -0
- package/src/tests/check-pr-body.test.ts +0 -23
- package/src/tests/credential-check.test.ts +38 -0
- package/src/tests/fleet-benchmark.test.ts +122 -2
- package/src/tests/http-users.test.ts +62 -1
- package/src/tests/model-catalog-table.test.ts +63 -0
- package/src/tests/model-profiles-api.test.ts +19 -7
- package/src/tests/models-catalog.test.ts +50 -0
- package/src/tests/onboarding.test.ts +21 -0
- package/src/tests/org-website.test.ts +62 -0
- package/src/tests/pi-mono-adapter.test.ts +23 -0
- package/src/tests/pr-body-leaks.test.ts +4 -0
- package/src/tests/pr-room-guard.test.ts +242 -0
- package/src/tests/ranking-listing.test.ts +8 -23
- package/src/tests/ranking-route.test.ts +49 -47
- package/src/tests/reasoning-effort.test.ts +39 -3
- package/src/tests/runner-harness-telemetry-env.test.ts +56 -1
- package/src/tests/swarm-tool-result-gate.test.ts +2 -4
- package/src/tests/telemetry-context.test.ts +128 -2
- package/src/tests/telemetry-ui-route.test.ts +123 -0
- package/src/tests/tool-annotations.test.ts +3 -2
- package/src/tests/used-by-route.test.ts +144 -10
- package/src/tests/workflow-agent-task-retry.test.ts +130 -4
- package/src/tests/workflow-wait-recovery.test.ts +116 -4
- package/src/tools/app-action-run.ts +63 -0
- package/src/tools/app-rows.ts +234 -0
- package/src/tools/model-catalog/index.ts +1 -1
- package/src/tools/tool-config.ts +8 -0
- package/src/tools/utils.ts +1 -1
- package/src/tools/workflows/retry-workflow-run.ts +1 -1
- package/src/types.ts +17 -0
- package/src/utils/company-profile.ts +24 -0
- package/src/utils/org-website.ts +58 -21
- package/src/workflows/recovery.ts +10 -22
- package/src/workflows/resume.ts +16 -0
- package/src/workflows/task-step-routing.ts +47 -7
- package/templates/skills/apps/SKILL.md +41 -2
- package/templates/skills/apps/content.md +41 -2
- package/dist/handlers-zbs90bny.js +0 -39
- package/dist/index-8pwc1jc8.js +0 -40
- package/dist/index-nxa6me0q.js +0 -41
- package/dist/lead-td8h2sfn.js +0 -78
- package/dist/worker-wr6xgfr2.js +0 -78
- package/src/tests/check-ranking-entry.test.ts +0 -146
package/src/http/ranking.ts
CHANGED
|
@@ -3,13 +3,9 @@ import { z } from "zod";
|
|
|
3
3
|
import { getDbClient, upsertSwarmConfig } from "../be/db";
|
|
4
4
|
import {
|
|
5
5
|
buildListing,
|
|
6
|
-
mintRankingClaim,
|
|
7
6
|
PUBLIC_RANKING_ENABLED_KEY,
|
|
8
7
|
RANKING_CATEGORIES,
|
|
9
|
-
rankingEntryFile,
|
|
10
8
|
rankingFormSchema,
|
|
11
|
-
rankingLeaveUrl,
|
|
12
|
-
rankingPrUrl,
|
|
13
9
|
readTelemetryRanking,
|
|
14
10
|
TELEMETRY_RANKING_KEY,
|
|
15
11
|
type TelemetryRanking,
|
|
@@ -23,14 +19,14 @@ import {
|
|
|
23
19
|
} from "../utils/org-identity";
|
|
24
20
|
import { ensureConfigAdmin } from "./config";
|
|
25
21
|
import { scheduleIntegrationsReload } from "./core";
|
|
22
|
+
import { globalConfig } from "./global-config";
|
|
26
23
|
import { route } from "./route-def";
|
|
27
|
-
import {
|
|
24
|
+
import { telemetryProxyEndpoint } from "./used-by";
|
|
28
25
|
|
|
29
26
|
// ─── Schemas ─────────────────────────────────────────────────────────────────
|
|
30
27
|
|
|
31
28
|
const ListingSchema = z.object({
|
|
32
29
|
v: z.literal(1),
|
|
33
|
-
claim: z.string(),
|
|
34
30
|
name: z.string(),
|
|
35
31
|
domain: z.string(),
|
|
36
32
|
category: z.enum(RANKING_CATEGORIES),
|
|
@@ -49,26 +45,21 @@ const RankingStateSchema = z.object({
|
|
|
49
45
|
name: z.string().nullable(),
|
|
50
46
|
domain: z.string().nullable(),
|
|
51
47
|
listing: ListingSchema.nullable(),
|
|
52
|
-
/** False when the stored listing was built for another website:
|
|
48
|
+
/** False when the stored listing was built for another website: Get ranked again. */
|
|
53
49
|
listingMatchesDomain: z.boolean(),
|
|
54
|
-
|
|
55
|
-
prUrl: z.string().nullable(),
|
|
50
|
+
/** The proxy page that checks whether the domain would be ranked. */
|
|
56
51
|
verifyUrl: z.string().nullable(),
|
|
57
52
|
});
|
|
58
53
|
export type RankingState = z.infer<typeof RankingStateSchema>;
|
|
59
54
|
|
|
60
55
|
const OptInResponseSchema = z.object({
|
|
61
56
|
domain: z.string(),
|
|
62
|
-
claim: z.string(),
|
|
63
57
|
listing: ListingSchema,
|
|
64
|
-
fileJson: z.string(),
|
|
65
|
-
prUrl: z.string(),
|
|
66
58
|
verifyUrl: z.string(),
|
|
67
59
|
});
|
|
68
60
|
|
|
69
61
|
const OptOutResponseSchema = z.object({
|
|
70
62
|
enabled: z.literal(false),
|
|
71
|
-
leaveUrl: z.string().nullable(),
|
|
72
63
|
});
|
|
73
64
|
|
|
74
65
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
@@ -79,7 +70,7 @@ const getRanking = route({
|
|
|
79
70
|
pattern: ["api", "ranking"],
|
|
80
71
|
summary: "Public ranking state",
|
|
81
72
|
description:
|
|
82
|
-
"Whether this install can join the public agent-swarm.dev ranking (telemetry on, organization name and website set), whether it is opted in, and its stored listing.
|
|
73
|
+
"Whether this install can join the public agent-swarm.dev ranking (telemetry on, organization name and website set), whether it is opted in, and its stored listing. Only a config admin can read it.",
|
|
83
74
|
tags: ["Telemetry"],
|
|
84
75
|
responses: {
|
|
85
76
|
200: { description: "Ranking state", schema: RankingStateSchema },
|
|
@@ -95,7 +86,7 @@ const optIn = route({
|
|
|
95
86
|
pattern: ["api", "ranking", "opt-in"],
|
|
96
87
|
summary: "Opt this install into the public ranking",
|
|
97
88
|
description:
|
|
98
|
-
"Builds the telemetry_ranking listing from the organization name and website plus the chosen category, stores it, turns PUBLIC_RANKING_ENABLED on and sends ranking.opted_in.
|
|
89
|
+
"Builds the telemetry_ranking listing from the organization name and website plus the chosen category, stores it, turns PUBLIC_RANKING_ENABLED on and sends ranking.opted_in. That is the whole opt-in: the install shows on agent-swarm.dev/ranking at the next hourly refresh.",
|
|
99
90
|
tags: ["Telemetry"],
|
|
100
91
|
body: rankingFormSchema,
|
|
101
92
|
responses: {
|
|
@@ -117,7 +108,7 @@ const optOut = route({
|
|
|
117
108
|
pattern: ["api", "ranking", "opt-out"],
|
|
118
109
|
summary: "Leave the public ranking",
|
|
119
110
|
description:
|
|
120
|
-
"Turns PUBLIC_RANKING_ENABLED off and sends ranking.opted_out, so workers stop sending ranking.usage.
|
|
111
|
+
"Turns PUBLIC_RANKING_ENABLED off and sends ranking.opted_out, so workers stop sending ranking.usage. The install leaves agent-swarm.dev/ranking at the next hourly refresh.",
|
|
121
112
|
tags: ["Telemetry"],
|
|
122
113
|
responses: {
|
|
123
114
|
200: { description: "Opted out", schema: OptOutResponseSchema },
|
|
@@ -163,11 +154,17 @@ async function telemetryReady(): Promise<boolean> {
|
|
|
163
154
|
return isTelemetryEnabled() && Boolean(await globalConfig("telemetry_installation_id"));
|
|
164
155
|
}
|
|
165
156
|
|
|
166
|
-
async function verifyUrl(
|
|
167
|
-
const params = new URLSearchParams({ domain
|
|
157
|
+
async function verifyUrl(domain: string): Promise<string> {
|
|
158
|
+
const params = new URLSearchParams({ domain });
|
|
168
159
|
return `${await telemetryProxyEndpoint("/v1/ranking/verify")}?${params.toString()}`;
|
|
169
160
|
}
|
|
170
161
|
|
|
162
|
+
/** The listing without the claim a v2.4.0 opt-in stored. */
|
|
163
|
+
function withoutClaim(listing: TelemetryRanking): Omit<TelemetryRanking, "claim"> {
|
|
164
|
+
const { claim: _claim, ...rest } = listing;
|
|
165
|
+
return rest;
|
|
166
|
+
}
|
|
167
|
+
|
|
171
168
|
async function setEnabled(enabled: boolean): Promise<void> {
|
|
172
169
|
await upsertSwarmConfig({
|
|
173
170
|
scope: "global",
|
|
@@ -179,7 +176,7 @@ async function setEnabled(enabled: boolean): Promise<void> {
|
|
|
179
176
|
function emitOptedIn(listing: TelemetryRanking): void {
|
|
180
177
|
telemetry.ranking(
|
|
181
178
|
"opted_in",
|
|
182
|
-
{ listing: JSON.stringify(listing) },
|
|
179
|
+
{ listing: JSON.stringify(withoutClaim(listing)) },
|
|
183
180
|
{ orgName: listing.name, orgWebsite: listing.domain },
|
|
184
181
|
);
|
|
185
182
|
}
|
|
@@ -204,17 +201,15 @@ export async function buildRankingState(): Promise<RankingState> {
|
|
|
204
201
|
enabled: enabled && listingMatchesDomain,
|
|
205
202
|
name: identity.name,
|
|
206
203
|
domain: identity.website,
|
|
207
|
-
listing,
|
|
204
|
+
listing: listing ? withoutClaim(listing) : null,
|
|
208
205
|
listingMatchesDomain,
|
|
209
|
-
|
|
210
|
-
prUrl: current ? rankingPrUrl(current) : null,
|
|
211
|
-
verifyUrl: current ? await verifyUrl(current) : null,
|
|
206
|
+
verifyUrl: current ? await verifyUrl(current.domain) : null,
|
|
212
207
|
};
|
|
213
208
|
}
|
|
214
209
|
|
|
215
210
|
/**
|
|
216
211
|
* Keep the listing in step with the org identity after a global config write.
|
|
217
|
-
* A renamed org rebuilds the listing
|
|
212
|
+
* A renamed org rebuilds the listing and re-sends it; a
|
|
218
213
|
* cleared or placeholder name, a changed or cleared website, or the setting
|
|
219
214
|
* turned off by hand opts the install out.
|
|
220
215
|
*/
|
|
@@ -238,7 +233,7 @@ export async function syncRankingAfterConfigChange(
|
|
|
238
233
|
if (identity.ok && identity.website === listing.domain) {
|
|
239
234
|
if (identity.name === listing.name) return;
|
|
240
235
|
try {
|
|
241
|
-
rebuilt = buildListing(identity, listing
|
|
236
|
+
rebuilt = buildListing(identity, listing);
|
|
242
237
|
} catch {
|
|
243
238
|
// A name the listing cannot carry (over 60 characters) leaves the ranking.
|
|
244
239
|
}
|
|
@@ -272,7 +267,6 @@ export async function handleRanking(
|
|
|
272
267
|
if (getRanking.match(req.method, pathSegments)) {
|
|
273
268
|
const parsed = await getRanking.parse(req, res, pathSegments, queryParams);
|
|
274
269
|
if (!parsed) return true;
|
|
275
|
-
// The state carries the claim and the PR that proves ownership of the listing.
|
|
276
270
|
if (!(await ensureConfigAdmin(req, res, "config.write.any"))) return true;
|
|
277
271
|
getRanking.respond(res, 200, await buildRankingState());
|
|
278
272
|
return true;
|
|
@@ -300,16 +294,12 @@ export async function handleRanking(
|
|
|
300
294
|
return true;
|
|
301
295
|
}
|
|
302
296
|
|
|
303
|
-
const website = identity.website;
|
|
304
297
|
const db = getDbClient();
|
|
305
|
-
//
|
|
306
|
-
// must return the same claim, or the one merged into community/ranking is lost.
|
|
298
|
+
// The listing and the flag land together, and the event fires only after both commit.
|
|
307
299
|
const built = await db.transaction(async () => {
|
|
308
|
-
const stored = await storedListing();
|
|
309
|
-
const claim = stored?.domain === website ? stored.claim : mintRankingClaim();
|
|
310
300
|
let listing: TelemetryRanking;
|
|
311
301
|
try {
|
|
312
|
-
listing = buildListing(identity, parsed.body
|
|
302
|
+
listing = buildListing(identity, parsed.body);
|
|
313
303
|
} catch (error) {
|
|
314
304
|
return { ok: false as const, error };
|
|
315
305
|
}
|
|
@@ -339,11 +329,8 @@ export async function handleRanking(
|
|
|
339
329
|
|
|
340
330
|
optIn.respond(res, 200, {
|
|
341
331
|
domain: listing.domain,
|
|
342
|
-
claim: listing.claim,
|
|
343
332
|
listing,
|
|
344
|
-
|
|
345
|
-
prUrl: rankingPrUrl(listing),
|
|
346
|
-
verifyUrl: await verifyUrl(listing),
|
|
333
|
+
verifyUrl: await verifyUrl(listing.domain),
|
|
347
334
|
});
|
|
348
335
|
return true;
|
|
349
336
|
}
|
|
@@ -356,10 +343,7 @@ export async function handleRanking(
|
|
|
356
343
|
await setEnabled(false);
|
|
357
344
|
if (listing) emitOptedOut(listing.domain);
|
|
358
345
|
scheduleIntegrationsReload();
|
|
359
|
-
optOut.respond(res, 200, {
|
|
360
|
-
enabled: false,
|
|
361
|
-
leaveUrl: listing ? rankingLeaveUrl(listing.domain) : null,
|
|
362
|
-
});
|
|
346
|
+
optOut.respond(res, 200, { enabled: false });
|
|
363
347
|
return true;
|
|
364
348
|
}
|
|
365
349
|
|
package/src/http/tasks.ts
CHANGED
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
SteeringSourceSchema,
|
|
74
74
|
SteerModeSchema,
|
|
75
75
|
SteerResultSchema,
|
|
76
|
+
SUPERSEDED_WORKFLOW_TASK_REASON,
|
|
76
77
|
splitLegacyModelAlias,
|
|
77
78
|
TaskAttachmentSchema,
|
|
78
79
|
} from "../types";
|
|
@@ -2014,7 +2015,7 @@ export async function handleTasks(
|
|
|
2014
2015
|
// Check this BEFORE the supersede UPDATE so we don't leave a workflow
|
|
2015
2016
|
// step in `superseded` if the engine expects `failed`.
|
|
2016
2017
|
if (task.workflowRunStepId != null) {
|
|
2017
|
-
const failed = await failTask(parsed.params.id,
|
|
2018
|
+
const failed = await failTask(parsed.params.id, SUPERSEDED_WORKFLOW_TASK_REASON);
|
|
2018
2019
|
ensure({
|
|
2019
2020
|
id: "task.workflow_step_failed_on_supersede",
|
|
2020
2021
|
flow: "task",
|
package/src/http/telemetry-ui.ts
CHANGED
|
@@ -43,7 +43,7 @@ const enableTelemetry = route({
|
|
|
43
43
|
description:
|
|
44
44
|
"Stores `ANONYMIZED_TELEMETRY=true` and applies it to the running server: the install ID is minted if needed and `telemetry.enabled` is sent once, so no restart is needed.",
|
|
45
45
|
tags: ["Telemetry"],
|
|
46
|
-
body: z.object({ via: z.enum(["banner", "settings"]).default("banner") }),
|
|
46
|
+
body: z.object({ via: z.enum(["banner", "settings", "benchmark"]).default("banner") }),
|
|
47
47
|
responses: {
|
|
48
48
|
200: {
|
|
49
49
|
description: "Telemetry is on",
|
package/src/http/used-by.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { getDbClient, upsertSwarmConfig } from "../be/db";
|
|
4
4
|
import { isTelemetryEnabled, trackRelayed } from "../telemetry";
|
|
5
|
+
import { USER_FUNCTIONS } from "../utils/company-profile";
|
|
5
6
|
import { orgIdentityStatus } from "../utils/org-identity";
|
|
6
7
|
import { normalizeOrgWebsite, TELEMETRY_PROXY_ORIGIN } from "../utils/org-website";
|
|
7
8
|
import { ensureConfigAdmin } from "./config";
|
|
8
9
|
import { scheduleIntegrationsReload } from "./core";
|
|
9
10
|
import { resolveHttpFavoriteOwner } from "./favorite-owner";
|
|
11
|
+
import { globalConfig } from "./global-config";
|
|
10
12
|
import { route } from "./route-def";
|
|
11
13
|
import { jsonError } from "./utils";
|
|
12
14
|
|
|
@@ -16,6 +18,9 @@ const CONSENT_AT_KEY = "SWARM_USED_BY_CONSENT_AT";
|
|
|
16
18
|
// still reaches the proxy after the name or website is changed or cleared.
|
|
17
19
|
const GRANTED_NAME_KEY = "SWARM_USED_BY_ORG_NAME";
|
|
18
20
|
const GRANTED_WEBSITE_KEY = "SWARM_USED_BY_ORG_WEBSITE";
|
|
21
|
+
const CONTACT_EMAIL_KEY = "SWARM_USED_BY_CONTACT_EMAIL";
|
|
22
|
+
const CONTACT_FUNCTION_KEY = "SWARM_USED_BY_CONTACT_FUNCTION";
|
|
23
|
+
const QUOTE_KEY = "SWARM_USED_BY_QUOTE";
|
|
19
24
|
const TIMEOUT_MS = 10_000;
|
|
20
25
|
|
|
21
26
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
@@ -26,17 +31,30 @@ const usedBy = route({
|
|
|
26
31
|
pattern: ["api", "used-by"],
|
|
27
32
|
summary: "Grant or revoke the 'used by' logo consent",
|
|
28
33
|
description:
|
|
29
|
-
"Records
|
|
34
|
+
"Records consent to show the organization's logo on agent-swarm.dev. A grant requires a valid contact email. It sends organization identity, contact details, and an optional quote to the proxy for manual review. This explicit admin action works when telemetry is off. A revoke clears the stored contact details and quote.",
|
|
30
35
|
tags: ["Telemetry"],
|
|
31
|
-
body: z
|
|
36
|
+
body: z
|
|
37
|
+
.object({
|
|
38
|
+
granted: z.boolean(),
|
|
39
|
+
contactEmail: z
|
|
40
|
+
.string()
|
|
41
|
+
.max(320, "Contact email must be at most 320 characters")
|
|
42
|
+
.email("Contact email must be a valid email address")
|
|
43
|
+
.optional(),
|
|
44
|
+
contactFunction: z.enum(USER_FUNCTIONS).optional(),
|
|
45
|
+
quote: z.string().max(280).optional(),
|
|
46
|
+
})
|
|
47
|
+
.refine((body) => !body.granted || body.contactEmail !== undefined, {
|
|
48
|
+
path: ["contactEmail"],
|
|
49
|
+
message: "Contact email is required when granting logo consent",
|
|
50
|
+
}),
|
|
32
51
|
responses: {
|
|
33
52
|
200: {
|
|
34
53
|
description: "Consent recorded",
|
|
35
54
|
schema: z.object({ granted: z.boolean(), changedAt: z.string() }),
|
|
36
55
|
},
|
|
37
56
|
400: {
|
|
38
|
-
description:
|
|
39
|
-
"Organization name or website is not set (a revoke falls back to the identity of the last grant)",
|
|
57
|
+
description: "Invalid contact details, or missing organization name or website",
|
|
40
58
|
},
|
|
41
59
|
401: { description: "Unauthorized" },
|
|
42
60
|
403: { description: "Only a config admin can change the consent" },
|
|
@@ -47,12 +65,6 @@ const usedBy = route({
|
|
|
47
65
|
|
|
48
66
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
49
67
|
|
|
50
|
-
/** A global config value, falling back to the process env. */
|
|
51
|
-
export async function globalConfig(key: string): Promise<string | undefined> {
|
|
52
|
-
const stored = (await getSwarmConfigs({ scope: "global", key }))?.[0]?.value?.trim();
|
|
53
|
-
return stored || process.env[key]?.trim() || undefined;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
68
|
/** A proxy path next to the configured `/v1/feedback` endpoint, so a stubbed proxy gets every route. */
|
|
57
69
|
export async function telemetryProxyEndpoint(path: `/v1/${string}`): Promise<string> {
|
|
58
70
|
const feedback = await globalConfig("feedback_endpoint");
|
|
@@ -80,7 +92,7 @@ export async function handleUsedBy(
|
|
|
80
92
|
if (!parsed) return true;
|
|
81
93
|
if (!(await ensureConfigAdmin(req, res, "config.write.any"))) return true;
|
|
82
94
|
|
|
83
|
-
const { granted } = parsed.body;
|
|
95
|
+
const { granted, contactEmail, contactFunction, quote } = parsed.body;
|
|
84
96
|
// The shared identity reader. The grant keeps its own rule (any non-empty
|
|
85
97
|
// name), so it does not apply the ranking's placeholder-name check.
|
|
86
98
|
const current = orgIdentityStatus({
|
|
@@ -116,6 +128,9 @@ export async function handleUsedBy(
|
|
|
116
128
|
org_website: orgWebsite,
|
|
117
129
|
...(orgDomain ? { org_domain: orgDomain } : {}),
|
|
118
130
|
granted,
|
|
131
|
+
...(granted
|
|
132
|
+
? { contact_email: contactEmail, contact_function: contactFunction, quote }
|
|
133
|
+
: {}),
|
|
119
134
|
changed_at: changedAt,
|
|
120
135
|
}),
|
|
121
136
|
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
@@ -129,18 +144,39 @@ export async function handleUsedBy(
|
|
|
129
144
|
return true;
|
|
130
145
|
}
|
|
131
146
|
|
|
132
|
-
await
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
await getDbClient().transaction(async () => {
|
|
148
|
+
await upsertSwarmConfig({ scope: "global", key: CONSENT_KEY, value: String(granted) });
|
|
149
|
+
await upsertSwarmConfig({ scope: "global", key: CONSENT_AT_KEY, value: changedAt });
|
|
150
|
+
if (granted) {
|
|
151
|
+
await upsertSwarmConfig({ scope: "global", key: GRANTED_NAME_KEY, value: orgName });
|
|
152
|
+
await upsertSwarmConfig({ scope: "global", key: GRANTED_WEBSITE_KEY, value: orgWebsite });
|
|
153
|
+
}
|
|
154
|
+
// Contact details stay out of agent env. The email is also a secret row,
|
|
155
|
+
// so `GET /api/config` masks it for every reader.
|
|
156
|
+
for (const [key, value, isSecret] of [
|
|
157
|
+
[CONTACT_EMAIL_KEY, contactEmail, true],
|
|
158
|
+
[CONTACT_FUNCTION_KEY, contactFunction, false],
|
|
159
|
+
[QUOTE_KEY, quote, false],
|
|
160
|
+
] as const) {
|
|
161
|
+
await upsertSwarmConfig({
|
|
162
|
+
scope: "global",
|
|
163
|
+
key,
|
|
164
|
+
value: granted ? (value ?? "") : "",
|
|
165
|
+
isSecret,
|
|
166
|
+
exportToEnv: false,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
138
170
|
scheduleIntegrationsReload();
|
|
139
171
|
|
|
140
172
|
const owner = await resolveHttpFavoriteOwner(req, myAgentId);
|
|
141
173
|
trackRelayed(
|
|
142
174
|
"used_by.consent_changed",
|
|
143
|
-
{
|
|
175
|
+
{
|
|
176
|
+
granted,
|
|
177
|
+
has_quote: granted && Boolean(quote),
|
|
178
|
+
has_function: granted && Boolean(contactFunction),
|
|
179
|
+
},
|
|
144
180
|
{ actor: owner?.userId ? { userId: owner.userId } : undefined, emitter: "ui" },
|
|
145
181
|
);
|
|
146
182
|
usedBy.respond(res, 200, { granted, changedAt });
|
package/src/http/users.ts
CHANGED
|
@@ -205,7 +205,7 @@ const createUserRoute = route({
|
|
|
205
205
|
tags: ["Users"],
|
|
206
206
|
body: z.object({
|
|
207
207
|
name: z.string().min(1),
|
|
208
|
-
email: z.string().optional(),
|
|
208
|
+
email: z.string().email("Email must be a valid email address").optional(),
|
|
209
209
|
role: z.string().optional(),
|
|
210
210
|
notes: z.string().optional(),
|
|
211
211
|
emailAliases: z.array(z.string()).optional(),
|
|
@@ -307,7 +307,7 @@ const updateUserRoute = route({
|
|
|
307
307
|
body: z
|
|
308
308
|
.object({
|
|
309
309
|
name: z.string().min(1).optional(),
|
|
310
|
-
email: z.string().optional(),
|
|
310
|
+
email: z.string().email("Email must be a valid email address").nullable().optional(),
|
|
311
311
|
role: z.string().optional(),
|
|
312
312
|
notes: z.string().optional(),
|
|
313
313
|
emailAliases: z.array(z.string()).optional(),
|
|
@@ -44,7 +44,7 @@ import type {
|
|
|
44
44
|
* default; the image installs exactly this version and the per-task settings
|
|
45
45
|
* set `amp.updates.mode: "disabled"`. Bump it deliberately, with a live run.
|
|
46
46
|
*/
|
|
47
|
-
export const AMP_PACKAGE = "@ampcode/cli@0.0.
|
|
47
|
+
export const AMP_PACKAGE = "@ampcode/cli@0.0.1792368068-g91990d";
|
|
48
48
|
|
|
49
49
|
/** MCP server name. Amp exposes its tools as `agent_swarm` / `store_progress` (dashes become underscores). */
|
|
50
50
|
const AMP_MCP_SERVER_NAME = "agent-swarm";
|
|
@@ -115,6 +115,7 @@ function modelToCredKeys(modelStr: string | undefined): string[] | null {
|
|
|
115
115
|
if (provider === "openrouter") return ["OPENROUTER_API_KEY"];
|
|
116
116
|
if (provider === "openai") return ["OPENAI_API_KEY"];
|
|
117
117
|
if (provider === "google") return ["GOOGLE_API_KEY", "GEMINI_API_KEY"];
|
|
118
|
+
if (provider === "opencode-go") return ["OPENCODE_API_KEY"];
|
|
118
119
|
// models.json custom providers (`writeSessionModelsJson`). The
|
|
119
120
|
// runner normalizes key aliases (HELMCODE_API_NAN → NAN_API_KEY), but a
|
|
120
121
|
// worker without that step (or a boot-time check) may only see the alias.
|
|
@@ -145,6 +146,19 @@ function getHarnessDrivableBedrockModels(): Array<{ id: string; name: string }>
|
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
/**
|
|
150
|
+
* The `opencode-go` model ids this pi-ai build resolves. models.dev can list
|
|
151
|
+
* ids pi-ai does not know yet, and pi runs its default model for those, so the
|
|
152
|
+
* worker reports this list and the picker offers only these ids.
|
|
153
|
+
*/
|
|
154
|
+
export function listPiOpencodeGoModelIds(): string[] {
|
|
155
|
+
try {
|
|
156
|
+
return getModels("opencode-go").map((m) => m.id);
|
|
157
|
+
} catch {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
148
162
|
/**
|
|
149
163
|
* Enumerate the Bedrock models that are both invocable by this AWS account and
|
|
150
164
|
* drivable by the pi-ai Converse harness, and verify the credential chain in
|
|
@@ -480,6 +494,7 @@ const PI_RUNTIME_API_KEYS: readonly (readonly [envKey: string, provider: string]
|
|
|
480
494
|
["OPENAI_API_KEY", "openai"],
|
|
481
495
|
["GEMINI_API_KEY", "google"],
|
|
482
496
|
["GOOGLE_API_KEY", "google"],
|
|
497
|
+
["OPENCODE_API_KEY", "opencode-go"],
|
|
483
498
|
// models.json custom providers (the registry). A runtime key beats the
|
|
484
499
|
// file's `apiKey: "$NAN_API_KEY"`, which pi would otherwise read from the
|
|
485
500
|
// shared process.env, where a credential pool is still the raw comma list.
|
|
@@ -168,7 +168,8 @@ function buildOpencodeReasoningOptions(
|
|
|
168
168
|
// qualitative level — translate internally (see "What We're NOT Doing" in
|
|
169
169
|
// the plan: no numeric budget surface for operators, only this
|
|
170
170
|
// adapter-internal transport detail).
|
|
171
|
-
|
|
171
|
+
// Its Anthropic transport reads `effort` into `output_config.effort`.
|
|
172
|
+
if (level === "max") return { effort: level };
|
|
172
173
|
return { thinking: { type: "enabled", budgetTokens: ANTHROPIC_BUDGET_TOKENS_BY_LEVEL[level] } };
|
|
173
174
|
}
|
|
174
175
|
if (providerId === "openrouter") {
|
package/src/providers/types.ts
CHANGED
|
@@ -320,6 +320,8 @@ export interface CredStatus {
|
|
|
320
320
|
* string signals Bedrock mode with `AWS_REGION` unset (no region fabricated).
|
|
321
321
|
*/
|
|
322
322
|
bedrockRegion?: string;
|
|
323
|
+
/** Pi-mono only: the `opencode-go` model ids pi-ai resolves. Undefined for other harnesses. */
|
|
324
|
+
opencodeGoModels?: string[];
|
|
323
325
|
}
|
|
324
326
|
|
|
325
327
|
/**
|
|
@@ -23,8 +23,6 @@ export const RANKING_CATEGORIES = Object.keys(RANKING_TAXONOMY) as [
|
|
|
23
23
|
keyof typeof RANKING_TAXONOMY,
|
|
24
24
|
...(keyof typeof RANKING_TAXONOMY)[],
|
|
25
25
|
];
|
|
26
|
-
export const RANKING_CLAIM_PATTERN = /^rk_[0-9a-f]{32}$/;
|
|
27
|
-
|
|
28
26
|
const hostname = z.string().refine((v) => normalizeOrgWebsite(v) === v, "bare hostname");
|
|
29
27
|
const nullableText = (max: number) => z.string().trim().min(1).max(max).nullable();
|
|
30
28
|
|
|
@@ -37,7 +35,11 @@ function inCategory(category: string, subcategory: string | null): boolean {
|
|
|
37
35
|
export const telemetryRankingV1 = z
|
|
38
36
|
.strictObject({
|
|
39
37
|
v: z.literal(1),
|
|
40
|
-
|
|
38
|
+
/** Minted by v2.4.0 for the retired ranking PR. Still parsed, never written; the proxy ignores it. */
|
|
39
|
+
claim: z
|
|
40
|
+
.string()
|
|
41
|
+
.regex(/^rk_[0-9a-f]{32}$/)
|
|
42
|
+
.optional(),
|
|
41
43
|
name: z.string().trim().min(1).max(60),
|
|
42
44
|
domain: hostname,
|
|
43
45
|
category: z.enum(RANKING_CATEGORIES),
|
|
@@ -88,12 +90,6 @@ export const rankingFormSchema = z.object({
|
|
|
88
90
|
});
|
|
89
91
|
export type RankingForm = z.infer<typeof rankingFormSchema>;
|
|
90
92
|
|
|
91
|
-
/** `rk_` + 32 lowercase hex characters from the platform CSPRNG. */
|
|
92
|
-
export function mintRankingClaim(): string {
|
|
93
|
-
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
94
|
-
return `rk_${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
93
|
const blankToNull = (value: string | null | undefined) => value?.trim() || null;
|
|
98
94
|
|
|
99
95
|
/**
|
|
@@ -104,7 +100,6 @@ const blankToNull = (value: string | null | undefined) => value?.trim() || null;
|
|
|
104
100
|
export function buildListing(
|
|
105
101
|
identity: OrgIdentityStatus,
|
|
106
102
|
form: RankingForm,
|
|
107
|
-
claim: string,
|
|
108
103
|
now: Date = new Date(),
|
|
109
104
|
): TelemetryRanking {
|
|
110
105
|
if (!identity.ok || !identity.name || !identity.website) {
|
|
@@ -112,7 +107,6 @@ export function buildListing(
|
|
|
112
107
|
}
|
|
113
108
|
const listing = {
|
|
114
109
|
v: 1 as const,
|
|
115
|
-
claim,
|
|
116
110
|
name: identity.name,
|
|
117
111
|
domain: identity.website,
|
|
118
112
|
category: form.category,
|
|
@@ -123,25 +117,3 @@ export function buildListing(
|
|
|
123
117
|
};
|
|
124
118
|
return parseTelemetryRanking(JSON.stringify(listing));
|
|
125
119
|
}
|
|
126
|
-
|
|
127
|
-
/** The `community/ranking/<domain>.json` file that approves this install. */
|
|
128
|
-
export function rankingEntryFile(listing: Pick<TelemetryRanking, "domain" | "claim">): string {
|
|
129
|
-
return `${JSON.stringify({ $schema: "./schema.json", domain: listing.domain, claim: listing.claim }, null, 2)}\n`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export const RANKING_REPO = "desplega-ai/agent-swarm";
|
|
133
|
-
|
|
134
|
-
/** GitHub's "new file" page, prefilled with the entry, as a PR from the admin's fork. */
|
|
135
|
-
export function rankingPrUrl(listing: Pick<TelemetryRanking, "domain" | "claim">): string {
|
|
136
|
-
const params = new URLSearchParams({
|
|
137
|
-
filename: `community/ranking/${listing.domain}.json`,
|
|
138
|
-
value: rankingEntryFile(listing),
|
|
139
|
-
message: `chore(ranking): add ${listing.domain}`,
|
|
140
|
-
});
|
|
141
|
-
return `https://github.com/${RANKING_REPO}/new/main?${params.toString()}`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** GitHub's delete page for an entry, to leave the ranking for good. */
|
|
145
|
-
export function rankingLeaveUrl(domain: string): string {
|
|
146
|
-
return `https://github.com/${RANKING_REPO}/delete/main/community/ranking/${domain}.json`;
|
|
147
|
-
}
|
|
@@ -180,6 +180,13 @@ export const SDK_TOOL_NAME_MAP = {
|
|
|
180
180
|
app_list: "app-list",
|
|
181
181
|
app_patch: "app-patch",
|
|
182
182
|
app_query: "app-query",
|
|
183
|
+
app_rows_list: "app-rows-list",
|
|
184
|
+
app_row_get: "app-row-get",
|
|
185
|
+
app_row_create: "app-row-create",
|
|
186
|
+
app_rows_create: "app-rows-create",
|
|
187
|
+
app_row_patch: "app-row-patch",
|
|
188
|
+
app_row_delete: "app-row-delete",
|
|
189
|
+
app_rows_delete: "app-rows-delete",
|
|
183
190
|
app_rollback: "app-rollback",
|
|
184
191
|
app_sync: "app-sync",
|
|
185
192
|
app_upsert: "app-upsert",
|
|
@@ -658,6 +658,37 @@ declare module "swarm-sdk" {
|
|
|
658
658
|
query: string;
|
|
659
659
|
params?: Record<string, string | number | boolean>;
|
|
660
660
|
}): Promise<unknown>;
|
|
661
|
+
app_rows_list(args: {
|
|
662
|
+
appId: string;
|
|
663
|
+
model: string;
|
|
664
|
+
equals?: Record<string, string | number | boolean>;
|
|
665
|
+
sort?: `${string}:asc` | `${string}:desc`;
|
|
666
|
+
limit?: number;
|
|
667
|
+
}): Promise<unknown>;
|
|
668
|
+
app_row_get(args: { appId: string; model: string; rowId: string }): Promise<unknown>;
|
|
669
|
+
app_row_create(args: {
|
|
670
|
+
appId: string;
|
|
671
|
+
model: string;
|
|
672
|
+
values: Record<string, unknown>;
|
|
673
|
+
}): Promise<unknown>;
|
|
674
|
+
app_rows_create(args: {
|
|
675
|
+
appId: string;
|
|
676
|
+
model: string;
|
|
677
|
+
rows: Record<string, unknown>[];
|
|
678
|
+
}): Promise<unknown>;
|
|
679
|
+
app_row_patch(args: {
|
|
680
|
+
appId: string;
|
|
681
|
+
model: string;
|
|
682
|
+
rowId: string;
|
|
683
|
+
values: Record<string, unknown>;
|
|
684
|
+
}): Promise<unknown>;
|
|
685
|
+
app_row_delete(args: { appId: string; model: string; rowId: string }): Promise<unknown>;
|
|
686
|
+
app_rows_delete(args: {
|
|
687
|
+
appId: string;
|
|
688
|
+
model: string;
|
|
689
|
+
equals: Record<string, string | number | boolean>;
|
|
690
|
+
limit?: number;
|
|
691
|
+
}): Promise<unknown>;
|
|
661
692
|
app_rollback(args: {
|
|
662
693
|
appId: string;
|
|
663
694
|
version: number;
|
|
@@ -640,6 +640,37 @@ declare module "swarm-sdk" {
|
|
|
640
640
|
query: string;
|
|
641
641
|
params?: Record<string, string | number | boolean>;
|
|
642
642
|
}): Promise<unknown>;
|
|
643
|
+
app_rows_list(args: {
|
|
644
|
+
appId: string;
|
|
645
|
+
model: string;
|
|
646
|
+
equals?: Record<string, string | number | boolean>;
|
|
647
|
+
sort?: `${string}:asc` | `${string}:desc`;
|
|
648
|
+
limit?: number;
|
|
649
|
+
}): Promise<unknown>;
|
|
650
|
+
app_row_get(args: { appId: string; model: string; rowId: string }): Promise<unknown>;
|
|
651
|
+
app_row_create(args: {
|
|
652
|
+
appId: string;
|
|
653
|
+
model: string;
|
|
654
|
+
values: Record<string, unknown>;
|
|
655
|
+
}): Promise<unknown>;
|
|
656
|
+
app_rows_create(args: {
|
|
657
|
+
appId: string;
|
|
658
|
+
model: string;
|
|
659
|
+
rows: Record<string, unknown>[];
|
|
660
|
+
}): Promise<unknown>;
|
|
661
|
+
app_row_patch(args: {
|
|
662
|
+
appId: string;
|
|
663
|
+
model: string;
|
|
664
|
+
rowId: string;
|
|
665
|
+
values: Record<string, unknown>;
|
|
666
|
+
}): Promise<unknown>;
|
|
667
|
+
app_row_delete(args: { appId: string; model: string; rowId: string }): Promise<unknown>;
|
|
668
|
+
app_rows_delete(args: {
|
|
669
|
+
appId: string;
|
|
670
|
+
model: string;
|
|
671
|
+
equals: Record<string, string | number | boolean>;
|
|
672
|
+
limit?: number;
|
|
673
|
+
}): Promise<unknown>;
|
|
643
674
|
app_rollback(args: {
|
|
644
675
|
appId: string;
|
|
645
676
|
version: number;
|
package/src/server.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { resolveTemplate } from "./prompts/resolver";
|
|
|
11
11
|
import { isRbacEnabled } from "./rbac";
|
|
12
12
|
import { getSlackConfiguration } from "./slack/config";
|
|
13
13
|
import { registerAcceptSteerTool } from "./tools/accept-steer";
|
|
14
|
+
import { registerAppActionRunTool } from "./tools/app-action-run";
|
|
14
15
|
import { registerAppDiffTool } from "./tools/app-diff";
|
|
15
16
|
import { registerAppGetTool } from "./tools/app-get";
|
|
16
17
|
import { registerAppHistoryTool } from "./tools/app-history";
|
|
@@ -18,6 +19,7 @@ import { registerAppListTool } from "./tools/app-list";
|
|
|
18
19
|
import { registerAppPatchTool } from "./tools/app-patch";
|
|
19
20
|
import { registerAppQueryTool } from "./tools/app-query";
|
|
20
21
|
import { registerAppRollbackTool } from "./tools/app-rollback";
|
|
22
|
+
import { registerAppRowTools } from "./tools/app-rows";
|
|
21
23
|
import { registerAppSyncTool } from "./tools/app-sync";
|
|
22
24
|
import { registerAppUpsertTool } from "./tools/app-upsert";
|
|
23
25
|
import { registerCancelApprovalRequestTool } from "./tools/cancel-approval-request";
|
|
@@ -643,6 +645,8 @@ export async function createServer(
|
|
|
643
645
|
// Pages capability - DB-backed lightweight artifacts (HTML / JSON specs).
|
|
644
646
|
if (hasCapability("pages")) {
|
|
645
647
|
registerAppGetTool(server);
|
|
648
|
+
registerAppRowTools(server);
|
|
649
|
+
registerAppActionRunTool(server);
|
|
646
650
|
registerAppHistoryTool(server);
|
|
647
651
|
registerAppDiffTool(server);
|
|
648
652
|
registerAppListTool(server);
|