@tianshu-ai/tianshu 0.4.19 → 0.4.21
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/package.json +1 -1
- package/packages/server/builtinConfig/plugins/web-search/manifest.json +52 -17
- package/packages/server/builtinConfig/plugins/web-search/skills/web-search-howto.md +36 -15
- package/packages/web/dist/assets/{bundle-web-CL_xD3_1.js → bundle-web-hHh7gz2L.js} +1 -1
- package/packages/web/dist/assets/{index-CmlY5kSR.js → index-B6oq6ed_.js} +4 -4
- package/packages/web/dist/assets/index-DWOCI_kD.css +2 -0
- package/packages/web/dist/index.html +2 -2
- package/plugins/web-search/dist/server.d.ts.map +1 -1
- package/plugins/web-search/dist/server.js +34 -12
- package/plugins/web-search/dist/server.js.map +1 -1
- package/plugins/web-search/dist/tools/health.d.ts +2 -1
- package/plugins/web-search/dist/tools/health.d.ts.map +1 -1
- package/plugins/web-search/dist/tools/health.js.map +1 -1
- package/plugins/web-search/dist/tools/index.d.ts +3 -2
- package/plugins/web-search/dist/tools/index.d.ts.map +1 -1
- package/plugins/web-search/dist/tools/index.js +2 -1
- package/plugins/web-search/dist/tools/index.js.map +1 -1
- package/plugins/web-search/dist/tools/providers.d.ts +11 -4
- package/plugins/web-search/dist/tools/providers.d.ts.map +1 -1
- package/plugins/web-search/dist/tools/providers.js +279 -0
- package/plugins/web-search/dist/tools/providers.js.map +1 -1
- package/plugins/web-search/dist/tools/web-fetch.d.ts +9 -0
- package/plugins/web-search/dist/tools/web-fetch.d.ts.map +1 -0
- package/plugins/web-search/dist/tools/web-fetch.js +258 -0
- package/plugins/web-search/dist/tools/web-fetch.js.map +1 -0
- package/plugins/web-search/dist/tools/web-search.d.ts +20 -1
- package/plugins/web-search/dist/tools/web-search.d.ts.map +1 -1
- package/plugins/web-search/dist/tools/web-search.js +92 -39
- package/plugins/web-search/dist/tools/web-search.js.map +1 -1
- package/plugins/web-search/manifest.json +52 -17
- package/plugins/web-search/package.json +2 -2
- package/plugins/web-search/skills/web-search-howto.md +36 -15
- package/plugins/workboard/dist/client.js +2 -2
- package/plugins/workboard/dist/client.js.map +1 -1
- package/packages/web/dist/assets/index-CsPw69WQ.css +0 -2
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// keys (401/403) don't trigger fallback — that's a config problem
|
|
28
28
|
// the user needs to fix, not a runtime hiccup.
|
|
29
29
|
import { Type } from "typebox";
|
|
30
|
-
import { braveProvider, tavilyProvider, } from "./providers.js";
|
|
30
|
+
import { braveProvider, hostedProvider, searxngProvider, tavilyProvider, } from "./providers.js";
|
|
31
31
|
export function buildWebSearchTool(cfg, health) {
|
|
32
32
|
return {
|
|
33
33
|
schema: {
|
|
@@ -60,13 +60,18 @@ export function buildWebSearchTool(cfg, health) {
|
|
|
60
60
|
], {
|
|
61
61
|
description: "Recency filter. Default is no filter (all results, ranked by relevance).",
|
|
62
62
|
})),
|
|
63
|
-
provider: Type.Optional(Type.Union([
|
|
64
|
-
|
|
63
|
+
provider: Type.Optional(Type.Union([
|
|
64
|
+
Type.Literal("hosted"),
|
|
65
|
+
Type.Literal("searxng"),
|
|
66
|
+
Type.Literal("tavily"),
|
|
67
|
+
Type.Literal("brave"),
|
|
68
|
+
], {
|
|
69
|
+
description: "Force a specific provider. Default uses the scheme the host configured.",
|
|
65
70
|
})),
|
|
66
71
|
}),
|
|
67
72
|
},
|
|
68
73
|
available(_ctx) {
|
|
69
|
-
return
|
|
74
|
+
return isConfigured(cfg);
|
|
70
75
|
},
|
|
71
76
|
async execute(rawArgs, _ctx) {
|
|
72
77
|
const args = rawArgs;
|
|
@@ -84,7 +89,10 @@ export function buildWebSearchTool(cfg, health) {
|
|
|
84
89
|
if (fullOrder.length === 0) {
|
|
85
90
|
return {
|
|
86
91
|
ok: false,
|
|
87
|
-
text: "web_search
|
|
92
|
+
text: "web_search is not configured. Open Settings → Plugins → Web " +
|
|
93
|
+
"Search and pick a scheme: \"hosted\" (key-free, Exa/Parallel), " +
|
|
94
|
+
"\"searxng\" (set your instance URL), or \"tavily\"/\"brave\" " +
|
|
95
|
+
"(set an API key).",
|
|
88
96
|
};
|
|
89
97
|
}
|
|
90
98
|
// Apply health cache: skip providers we already know are
|
|
@@ -168,52 +176,97 @@ export function readWebSearchConfig(raw) {
|
|
|
168
176
|
if (!raw || typeof raw !== "object")
|
|
169
177
|
return {};
|
|
170
178
|
const r = raw;
|
|
179
|
+
const str = (k) => typeof r[k] === "string" && r[k] ? r[k] : undefined;
|
|
180
|
+
const scheme = r.scheme === "hosted" ||
|
|
181
|
+
r.scheme === "searxng" ||
|
|
182
|
+
r.scheme === "tavily" ||
|
|
183
|
+
r.scheme === "brave"
|
|
184
|
+
? r.scheme
|
|
185
|
+
: undefined;
|
|
171
186
|
return {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
braveApiKey: typeof r.braveApiKey === "string" && r.braveApiKey
|
|
176
|
-
? r.braveApiKey
|
|
177
|
-
: undefined,
|
|
178
|
-
preferredProvider: r.preferredProvider === "tavily" || r.preferredProvider === "brave"
|
|
179
|
-
? r.preferredProvider
|
|
187
|
+
scheme,
|
|
188
|
+
hostedBackend: r.hostedBackend === "parallel" || r.hostedBackend === "exa"
|
|
189
|
+
? r.hostedBackend
|
|
180
190
|
: undefined,
|
|
191
|
+
exaApiKey: str("exaApiKey"),
|
|
192
|
+
parallelApiKey: str("parallelApiKey"),
|
|
193
|
+
searxngBaseUrl: str("searxngBaseUrl"),
|
|
194
|
+
tavilyApiKey: str("tavilyApiKey"),
|
|
195
|
+
braveApiKey: str("braveApiKey"),
|
|
181
196
|
timeoutMs: typeof r.timeoutMs === "number" && Number.isFinite(r.timeoutMs)
|
|
182
197
|
? r.timeoutMs
|
|
183
198
|
: undefined,
|
|
184
199
|
};
|
|
185
200
|
}
|
|
201
|
+
/** Resolve the effective scheme. Explicit `scheme` wins; otherwise
|
|
202
|
+
* infer from what's configured, preferring the key-free hosted
|
|
203
|
+
* scheme so a fresh install works out of the box. */
|
|
204
|
+
export function effectiveScheme(cfg) {
|
|
205
|
+
if (cfg.scheme)
|
|
206
|
+
return cfg.scheme;
|
|
207
|
+
if (cfg.searxngBaseUrl)
|
|
208
|
+
return "searxng";
|
|
209
|
+
if (cfg.tavilyApiKey)
|
|
210
|
+
return "tavily";
|
|
211
|
+
if (cfg.braveApiKey)
|
|
212
|
+
return "brave";
|
|
213
|
+
return "hosted"; // key-free default
|
|
214
|
+
}
|
|
215
|
+
/** True when the effective scheme has everything it needs to run. */
|
|
216
|
+
export function isConfigured(cfg) {
|
|
217
|
+
switch (effectiveScheme(cfg)) {
|
|
218
|
+
case "hosted":
|
|
219
|
+
return true; // key-free
|
|
220
|
+
case "searxng":
|
|
221
|
+
return Boolean(cfg.searxngBaseUrl);
|
|
222
|
+
case "tavily":
|
|
223
|
+
return Boolean(cfg.tavilyApiKey);
|
|
224
|
+
case "brave":
|
|
225
|
+
return Boolean(cfg.braveApiKey);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/** Pack the hosted provider's opaque `key` blob (backend + optional
|
|
229
|
+
* api key). See hostedProvider in providers.ts. */
|
|
230
|
+
function hostedKey(cfg) {
|
|
231
|
+
const backend = cfg.hostedBackend ?? "exa";
|
|
232
|
+
const apiKey = backend === "parallel" ? cfg.parallelApiKey : cfg.exaApiKey;
|
|
233
|
+
return JSON.stringify({ backend, apiKey });
|
|
234
|
+
}
|
|
186
235
|
/** Decide which providers to try, in order. Returns at most two
|
|
187
236
|
* entries (the configured pair, preferred first). */
|
|
188
237
|
function providerOrder(cfg, override) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
238
|
+
// Build the entry for a single scheme, or null when that scheme
|
|
239
|
+
// isn't usable (missing credential).
|
|
240
|
+
const entryFor = (scheme) => {
|
|
241
|
+
switch (scheme) {
|
|
242
|
+
case "hosted":
|
|
243
|
+
return { provider: hostedProvider, key: hostedKey(cfg) };
|
|
244
|
+
case "searxng":
|
|
245
|
+
return cfg.searxngBaseUrl
|
|
246
|
+
? { provider: searxngProvider, key: cfg.searxngBaseUrl }
|
|
247
|
+
: null;
|
|
248
|
+
case "tavily":
|
|
249
|
+
return cfg.tavilyApiKey
|
|
250
|
+
? { provider: tavilyProvider, key: cfg.tavilyApiKey }
|
|
251
|
+
: null;
|
|
252
|
+
case "brave":
|
|
253
|
+
return cfg.braveApiKey
|
|
254
|
+
? { provider: braveProvider, key: cfg.braveApiKey }
|
|
255
|
+
: null;
|
|
197
256
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (haveTavily)
|
|
206
|
-
order.push({ provider: tavilyProvider, key: cfg.tavilyApiKey });
|
|
207
|
-
if (haveBrave)
|
|
208
|
-
order.push({ provider: braveProvider, key: cfg.braveApiKey });
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
if (haveBrave)
|
|
212
|
-
order.push({ provider: braveProvider, key: cfg.braveApiKey });
|
|
213
|
-
if (haveTavily)
|
|
214
|
-
order.push({ provider: tavilyProvider, key: cfg.tavilyApiKey });
|
|
257
|
+
};
|
|
258
|
+
// Explicit per-call override: honour it if usable, else fall
|
|
259
|
+
// through to the configured scheme.
|
|
260
|
+
if (override) {
|
|
261
|
+
const e = entryFor(override);
|
|
262
|
+
if (e)
|
|
263
|
+
return [e];
|
|
215
264
|
}
|
|
216
|
-
|
|
265
|
+
// No cross-scheme fallback: the operator picked a scheme, we use
|
|
266
|
+
// it. (Mixing a self-hosted SearXNG with a paid Tavily fallback
|
|
267
|
+
// would be surprising.) Return the single effective scheme.
|
|
268
|
+
const e = entryFor(effectiveScheme(cfg));
|
|
269
|
+
return e ? [e] : [];
|
|
217
270
|
}
|
|
218
271
|
function formatSuccess(provider, query, results, priorErrors) {
|
|
219
272
|
const head = priorErrors.length === 0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../src/tools/web-search.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,mEAAmE;AACnE,8DAA8D;AAC9D,8DAA8D;AAC9D,gEAAgE;AAChE,iDAAiD;AACjD,EAAE;AACF,uBAAuB;AACvB,EAAE;AACF,MAAM;AACN,mBAAmB;AACnB,wBAAwB;AACxB,sBAAsB;AACtB,wCAAwC;AACxC,sCAAsC;AACtC,iEAAiE;AACjE,YAAY;AACZ,UAAU;AACV,QAAQ;AACR,MAAM;AACN,EAAE;AACF,gEAAgE;AAChE,gEAAgE;AAChE,mEAAmE;AACnE,+DAA+D;AAC/D,kEAAkE;AAClE,+CAA+C;AAE/C,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EACL,aAAa,EACb,cAAc,
|
|
1
|
+
{"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../src/tools/web-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "web-search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"displayName": "Web Search",
|
|
5
|
-
"description": "Web search
|
|
5
|
+
"description": "Web search + single-page fetch for agents. Pick a scheme: key-free hosted MCP (Exa/Parallel), self-hosted SearXNG, or keyed Tavily/Brave. web_fetch works with no config.",
|
|
6
6
|
"author": "tianshu-ai",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"permissions": ["network.external"],
|
|
9
9
|
"server": { "entry": "@tianshu-builtin/plugin-web-search/server" },
|
|
10
10
|
"contributes": {
|
|
11
11
|
"tools": [
|
|
12
|
-
{ "id": "web_search", "module": "WebSearchTool", "since": "0.1.0" }
|
|
12
|
+
{ "id": "web_search", "module": "WebSearchTool", "since": "0.1.0" },
|
|
13
|
+
{ "id": "web_fetch", "module": "WebFetchTool", "since": "0.2.0" }
|
|
13
14
|
],
|
|
14
15
|
"skills": [
|
|
15
16
|
{
|
|
@@ -24,30 +25,64 @@
|
|
|
24
25
|
},
|
|
25
26
|
"configSchema": {
|
|
26
27
|
"fields": [
|
|
28
|
+
{
|
|
29
|
+
"key": "scheme",
|
|
30
|
+
"label": "Search scheme",
|
|
31
|
+
"kind": "select",
|
|
32
|
+
"default": "hosted",
|
|
33
|
+
"options": [
|
|
34
|
+
{ "label": "Hosted MCP (key-free: Exa / Parallel)", "value": "hosted" },
|
|
35
|
+
{ "label": "SearXNG (self-hosted)", "value": "searxng" },
|
|
36
|
+
{ "label": "Tavily (API key)", "value": "tavily" },
|
|
37
|
+
{ "label": "Brave (API key)", "value": "brave" }
|
|
38
|
+
],
|
|
39
|
+
"description": "Which backend web_search uses. \"hosted\" needs no key (uses Exa/Parallel free MCP endpoints). \"searxng\" needs a base URL below. \"tavily\"/\"brave\" need the matching API key. web_fetch always works regardless of this setting."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"key": "hostedBackend",
|
|
43
|
+
"label": "Hosted backend",
|
|
44
|
+
"kind": "select",
|
|
45
|
+
"default": "exa",
|
|
46
|
+
"options": [
|
|
47
|
+
{ "label": "Exa", "value": "exa" },
|
|
48
|
+
{ "label": "Parallel", "value": "parallel" }
|
|
49
|
+
],
|
|
50
|
+
"description": "Only used when scheme = hosted. Which free MCP endpoint to query. Both work anonymously; add a key below only if you have one and want higher limits."
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"key": "searxngBaseUrl",
|
|
54
|
+
"label": "SearXNG base URL",
|
|
55
|
+
"kind": "string",
|
|
56
|
+
"placeholder": "https://searx.example.com",
|
|
57
|
+
"description": "Only used when scheme = searxng. Base URL of your SearXNG instance (its JSON API must be enabled: `search.formats: [json]` in settings.yml). No API key needed."
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"key": "exaApiKey",
|
|
61
|
+
"label": "Exa API key (optional)",
|
|
62
|
+
"kind": "secret",
|
|
63
|
+
"placeholder": "exa-...",
|
|
64
|
+
"description": "Optional. Only used when scheme = hosted and backend = Exa. Raises limits; the free endpoint works without it. Stored under <tenant>/secrets/, never returned to the browser."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"key": "parallelApiKey",
|
|
68
|
+
"label": "Parallel API key (optional)",
|
|
69
|
+
"kind": "secret",
|
|
70
|
+
"placeholder": "...",
|
|
71
|
+
"description": "Optional. Only used when scheme = hosted and backend = Parallel. Raises limits; the free endpoint works without it."
|
|
72
|
+
},
|
|
27
73
|
{
|
|
28
74
|
"key": "tavilyApiKey",
|
|
29
75
|
"label": "Tavily API key",
|
|
30
76
|
"kind": "secret",
|
|
31
77
|
"placeholder": "tvly-...",
|
|
32
|
-
"description": "Sign up at tavily.com (free tier 1000 searches/month). Stored under <tenant>/secrets/, never returned to the browser."
|
|
78
|
+
"description": "Only used when scheme = tavily. Sign up at tavily.com (free tier 1000 searches/month). Stored under <tenant>/secrets/, never returned to the browser."
|
|
33
79
|
},
|
|
34
80
|
{
|
|
35
81
|
"key": "braveApiKey",
|
|
36
82
|
"label": "Brave Search API key",
|
|
37
83
|
"kind": "secret",
|
|
38
84
|
"placeholder": "BSA...",
|
|
39
|
-
"description": "
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"key": "preferredProvider",
|
|
43
|
-
"label": "Preferred provider",
|
|
44
|
-
"kind": "select",
|
|
45
|
-
"default": "tavily",
|
|
46
|
-
"options": [
|
|
47
|
-
{ "label": "Tavily", "value": "tavily" },
|
|
48
|
-
{ "label": "Brave", "value": "brave" }
|
|
49
|
-
],
|
|
50
|
-
"description": "Tried first when both keys are set. The other provider is used as automatic fallback only on transient errors (network / 5xx / 429). Auth failures (401 / 403) park the bad key in the health cache; clear it from Settings after fixing the key."
|
|
85
|
+
"description": "Only used when scheme = brave. Get a free key at api-dashboard.search.brave.com (2000/month)."
|
|
51
86
|
},
|
|
52
87
|
{
|
|
53
88
|
"key": "timeoutMs",
|
|
@@ -58,7 +93,7 @@
|
|
|
58
93
|
"max": 60000,
|
|
59
94
|
"step": 500,
|
|
60
95
|
"default": 8000,
|
|
61
|
-
"description": "Network timeout for each
|
|
96
|
+
"description": "Network timeout for each web_search / web_fetch call. Increase if you hit timeouts on slow networks."
|
|
62
97
|
}
|
|
63
98
|
]
|
|
64
99
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tianshu-builtin/plugin-web-search",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"description": "Web search
|
|
5
|
+
"description": "Web search + fetch for tianshu agents. Schemes: key-free hosted MCP (Exa/Parallel), self-hosted SearXNG, or keyed Tavily/Brave.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/server.js",
|
|
8
8
|
"types": "./dist/server.d.ts",
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: web-search-howto
|
|
3
|
-
description: How to use
|
|
3
|
+
description: How to use `web_search` and `web_fetch` for tasks that need fresh information from the open web — current events, recent docs, prices, release notes, anything not in your training set or in the user's local files.
|
|
4
4
|
scope: worker
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Web search
|
|
7
|
+
# Web search & fetch
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
This plugin gives you two tools:
|
|
10
|
+
|
|
11
|
+
- **`web_search`** — returns a JSON array of `{title, url,
|
|
12
|
+
content, publishedDate}` results. The host picks the backend
|
|
13
|
+
scheme (you don't): key-free hosted MCP (Exa/Parallel),
|
|
14
|
+
a self-hosted SearXNG instance, or Tavily/Brave. Same result
|
|
15
|
+
shape regardless.
|
|
16
|
+
- **`web_fetch`** — fetches ONE URL and returns its readable
|
|
17
|
+
body as markdown or text. No API key, no JavaScript. Use it
|
|
18
|
+
to read a page you got from a search result.
|
|
19
|
+
|
|
20
|
+
## web_search
|
|
12
21
|
|
|
13
22
|
## Basic call
|
|
14
23
|
|
|
@@ -34,9 +43,9 @@ snippet is insufficient.
|
|
|
34
43
|
Biases engines toward language-specific sources. Skip this
|
|
35
44
|
for technical English-language queries; technical content is
|
|
36
45
|
usually English regardless of locale.
|
|
37
|
-
- `provider`: force `"
|
|
38
|
-
specific
|
|
39
|
-
|
|
46
|
+
- `provider`: force `"hosted"`, `"searxng"`, `"tavily"`, or
|
|
47
|
+
`"brave"` if you want a specific backend. Default is the
|
|
48
|
+
scheme the host configured. Usually leave it unset.
|
|
40
49
|
|
|
41
50
|
## Anti-patterns
|
|
42
51
|
|
|
@@ -52,14 +61,26 @@ snippet is insufficient.
|
|
|
52
61
|
cite. Agents who paste 10 result blocks turn answers into
|
|
53
62
|
noise.
|
|
54
63
|
|
|
55
|
-
##
|
|
64
|
+
## web_fetch — reading a page
|
|
65
|
+
|
|
66
|
+
`web_search` `content` is only 1-3 sentences. For the actual
|
|
67
|
+
page body, call `web_fetch`:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
web_fetch({ url: "https://example.com/article" })
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- `extractMode`: `"markdown"` (default) or `"text"`.
|
|
74
|
+
- `maxChars`: truncate the output (default 20000).
|
|
75
|
+
|
|
76
|
+
`web_fetch` does a plain HTTP GET and extracts readable
|
|
77
|
+
content — it does **not** run JavaScript. For JS-heavy or
|
|
78
|
+
login-gated pages, use the browser tools instead. It blocks
|
|
79
|
+
private/internal hosts, so you can't fetch `localhost` or
|
|
80
|
+
cloud metadata endpoints.
|
|
56
81
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
(`read_file` on a previously-saved page, the browser tools,
|
|
60
|
-
etc.). `web_search` itself does not return page bodies; that's
|
|
61
|
-
intentional — fetching only the URLs you actually need keeps
|
|
62
|
-
the tool fast and cheap.
|
|
82
|
+
Fetch only the URLs you actually need — one or two authoritative
|
|
83
|
+
pages beats fetching every result.
|
|
63
84
|
|
|
64
85
|
## Citing sources
|
|
65
86
|
|
|
@@ -399,14 +399,14 @@ function BoardCard({ task, meta, busy, compact, agentNames, onDragStart, onDragE
|
|
|
399
399
|
interventionReason: null,
|
|
400
400
|
interventionAt: null,
|
|
401
401
|
});
|
|
402
|
-
}, className: "shrink-0 rounded
|
|
402
|
+
}, className: "shrink-0 rounded bg-rose-600 px-1.5 py-px text-[9.5px] font-medium text-white hover:bg-rose-500 disabled:opacity-50", children: "Retry" })] })), (task.labels ?? []).includes("stalled") && (_jsxs("div", { className: "mt-1 flex items-start gap-1 rounded border border-orange-500/40 bg-orange-500/5 px-1.5 py-1 text-[10px] text-orange-200", title: task.failureReason ?? "", onClick: (e) => e.stopPropagation(), children: [_jsx(AlertTriangle, { className: "w-3 h-3 mt-px shrink-0" }), _jsxs("span", { className: "min-w-0 flex-1 break-words line-clamp-3", children: ["stalled", (task.attempts ?? 0) > 0 ? ` after ${task.attempts} attempts` : "", task.failureReason ? `: ${task.failureReason}` : ""] }), _jsx("button", { type: "button", disabled: busy, onClick: (e) => {
|
|
403
403
|
e.stopPropagation();
|
|
404
404
|
void onPatch(task.id, {
|
|
405
405
|
labels: (task.labels ?? []).filter((l) => l !== "stalled"),
|
|
406
406
|
attempts: 0,
|
|
407
407
|
failureReason: null,
|
|
408
408
|
});
|
|
409
|
-
}, className: "shrink-0 rounded
|
|
409
|
+
}, className: "shrink-0 rounded bg-orange-600 px-1.5 py-px text-[9.5px] font-medium text-white hover:bg-orange-500 disabled:opacity-50", children: "Retry" })] })), (task.labels ?? []).includes("draft") && (_jsxs("div", { className: "mt-1 flex items-center gap-1.5", onClick: (e) => e.stopPropagation(), children: [_jsx("span", { className: "inline-block rounded border border-yellow-500/40 bg-yellow-500/5 px-1.5 py-px text-[10px] text-yellow-200", children: "draft - pool will skip" }), _jsx("button", { type: "button", disabled: busy, onClick: (e) => {
|
|
410
410
|
e.stopPropagation();
|
|
411
411
|
void onPatch(task.id, {
|
|
412
412
|
labels: (task.labels ?? []).filter((l) => l !== "draft"),
|