@gobing-ai/knowledge-kit 0.0.19 → 0.0.22
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/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +161 -142
- package/package.json +1 -1
- package/plugins/generations/content-gen/dist/index.js +20 -3
- package/plugins/generations/core-facts-gen/dist/index.js +20 -3
- package/plugins/generations/daily-article-gen/dist/index.js +20 -3
- package/plugins/generations/dailynews-gen/dist/index.js +29 -4
- package/plugins/generations/dailynews-gen/src/script-builder.ts +19 -1
- package/plugins/generations/episode-plan-gen/dist/index.js +20 -3
- package/plugins/generations/image-gen/dist/index.js +147 -69
- package/plugins/generations/image-gen/src/presets.ts +2 -2
- package/plugins/generations/image-gen/src/providers/agnes.ts +6 -2
- package/plugins/generations/image-gen/src/providers/azure.ts +6 -2
- package/plugins/generations/image-gen/src/providers/dashscope.ts +10 -3
- package/plugins/generations/image-gen/src/providers/google.ts +70 -29
- package/plugins/generations/image-gen/src/providers/huggingface.ts +3 -0
- package/plugins/generations/image-gen/src/providers/jimeng.ts +9 -2
- package/plugins/generations/image-gen/src/providers/minimax.ts +10 -2
- package/plugins/generations/image-gen/src/providers/openai.ts +9 -3
- package/plugins/generations/image-gen/src/providers/openrouter.ts +16 -4
- package/plugins/generations/image-gen/src/providers/replicate.ts +13 -3
- package/plugins/generations/image-gen/src/providers/seedream.ts +4 -1
- package/plugins/generations/image-gen/src/providers/timeouts.ts +14 -0
- package/plugins/generations/image-gen/src/providers/types.ts +10 -0
- package/plugins/generations/image-gen/src/providers/zai.ts +4 -1
- package/plugins/generations/news-report-gen/dist/index.js +20 -3
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +13 -5
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/qc.py +23 -15
- package/plugins/generations/voice-gen/dist/index.js +36 -10
- package/plugins/generations/voice-gen/src/voicebox-client.ts +18 -4
- package/plugins/generations/voice-gen/src/voicebox-server.ts +2 -1
- package/plugins/ingestions/aihot-ingest/dist/index.js +26 -6
- package/plugins/ingestions/aihot-ingest/plugin.json +1 -1
- package/plugins/ingestions/aihot-ingest/src/client.ts +5 -0
- package/plugins/ingestions/aihot-ingest/src/rss.ts +12 -2
- package/plugins/ingestions/horizon-ingest/dist/index.js +20 -3
- package/plugins/ingestions/last30days-ingest/dist/index.js +20 -3
- package/plugins/ingestions/web-search/dist/index.js +22 -3
- package/plugins/ingestions/web-search/src/index.ts +4 -0
- package/plugins/kk/commands/workflow-run.md +20 -6
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/scripts/itc-stages.ts +563 -0
- package/plugins/kk/scripts/kk-workflow-stages.ts +125 -18
- package/plugins/kk/scripts/render-md.ts +7 -1
- package/plugins/kk/skills/article-adapt/SKILL.md +85 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +26 -16
- package/plugins/kk/workflows/kk-itc.yaml +461 -12
- package/plugins/publishings/emdash-pub/dist/index.js +76 -19
- package/plugins/publishings/emdash-pub/src/index.ts +4 -0
- package/plugins/publishings/infoq-pub/dist/index.js +74 -21
- package/plugins/publishings/juejin-pub/dist/index.js +74 -21
- package/plugins/publishings/medium-pub/dist/index.js +77 -19
- package/plugins/publishings/medium-pub/src/index.ts +5 -0
- package/plugins/publishings/podcast-pub/dist/index.js +130 -34
- package/plugins/publishings/podcast-pub/src/index.ts +20 -5
- package/plugins/publishings/podcast-pub/src/map.ts +11 -0
- package/plugins/publishings/podcast-pub/src/show-notes.ts +66 -13
- package/plugins/publishings/qiita-pub/dist/index.js +75 -18
- package/plugins/publishings/qiita-pub/src/index.ts +4 -0
- package/plugins/publishings/substack-pub/dist/index.js +74 -21
- package/plugins/publishings/surfdash-pub/dist/index.js +99 -62
- package/plugins/publishings/surfdash-pub/src/index.ts +60 -19
- package/plugins/publishings/wechatmp-pub/dist/index.js +79 -22
- package/plugins/publishings/wechatmp-pub/src/index.ts +12 -3
- package/plugins/publishings/x-pub/dist/index.js +56 -37
- package/plugins/publishings/x-pub/src/index.ts +4 -0
- package/plugins/publishings/xhs-pub/dist/index.js +74 -21
- package/plugins/publishings/zenn-pub/dist/index.js +103 -25
- package/plugins/publishings/zenn-pub/src/index.ts +43 -9
|
@@ -133,8 +133,8 @@ def _transcribe(backend: Backend, wav: bytes, language: str) -> str | None:
|
|
|
133
133
|
return None
|
|
134
134
|
|
|
135
135
|
|
|
136
|
-
def _render_verified(backend: Backend, spec: SegmentSpec) -> tuple[bytes, float, int, str | None, bool]:
|
|
137
|
-
"""Spec §5 verify-retry -> (wav, duration, verify_retries, transcription, loudness_dip)."""
|
|
136
|
+
def _render_verified(backend: Backend, spec: SegmentSpec) -> tuple[bytes, float, int, str | None, bool, float | None]:
|
|
137
|
+
"""Spec §5 verify-retry -> (wav, duration, verify_retries, transcription, loudness_dip, dip_at)."""
|
|
138
138
|
for attempt in range(MAX_VERIFY_RETRIES + 1):
|
|
139
139
|
final = attempt == MAX_VERIFY_RETRIES # the final attempt is always accepted
|
|
140
140
|
if attempt:
|
|
@@ -154,7 +154,7 @@ def _render_verified(backend: Backend, spec: SegmentSpec) -> tuple[bytes, float,
|
|
|
154
154
|
if dip and not final:
|
|
155
155
|
_log(f"loudness dip detected at {dip_at}s — regenerating segment")
|
|
156
156
|
continue
|
|
157
|
-
return wav, duration, attempt, transcription, dip
|
|
157
|
+
return wav, duration, attempt, transcription, dip, dip_at
|
|
158
158
|
raise AssertionError("unreachable: the final verify attempt always returns") # pragma: no cover
|
|
159
159
|
|
|
160
160
|
|
|
@@ -212,7 +212,7 @@ def _render(
|
|
|
212
212
|
"seed": None if segment.seed is None else int(segment.seed),
|
|
213
213
|
"speed": None if segment.speed is None else float(segment.speed),
|
|
214
214
|
}
|
|
215
|
-
wav, duration, retries, transcription, dip = _render_verified(backend, spec)
|
|
215
|
+
wav, duration, retries, transcription, dip, dip_at = _render_verified(backend, spec)
|
|
216
216
|
|
|
217
217
|
gap_ms = segment.gap_ms or 0
|
|
218
218
|
wavs.append(wav)
|
|
@@ -233,7 +233,15 @@ def _render(
|
|
|
233
233
|
}
|
|
234
234
|
)
|
|
235
235
|
)
|
|
236
|
-
audit_meta.append(
|
|
236
|
+
audit_meta.append(
|
|
237
|
+
{
|
|
238
|
+
"duration": duration,
|
|
239
|
+
"transcription": transcription,
|
|
240
|
+
"loudness_dip": dip,
|
|
241
|
+
"dip_at": dip_at,
|
|
242
|
+
"verify_retries": retries,
|
|
243
|
+
}
|
|
244
|
+
)
|
|
237
245
|
retry_note = f" ({retries} verify {'retry' if retries == 1 else 'retries'})" if retries else ""
|
|
238
246
|
_log(f"segment {index + 1}/{total} done in {monotonic() - segment_started:.1f}s{retry_note}")
|
|
239
247
|
|
|
@@ -48,6 +48,7 @@ class SegmentQualityAudit:
|
|
|
48
48
|
repetition_detected: bool
|
|
49
49
|
duration_anomaly: bool
|
|
50
50
|
fidelity_score: float | None
|
|
51
|
+
verify_retries: int = 0
|
|
51
52
|
issues: list[str] = field(default_factory=list)
|
|
52
53
|
|
|
53
54
|
|
|
@@ -158,21 +159,6 @@ def audit_voice_segments(
|
|
|
158
159
|
if fidelity < TRANSCRIPTION_FIDELITY_FLOOR:
|
|
159
160
|
issues.append(f"transcription_fidelity_low:{fidelity:.2f}")
|
|
160
161
|
|
|
161
|
-
# Repetition
|
|
162
|
-
repetition = detect_repetitions(text) or (
|
|
163
|
-
detect_repetitions(transcription) if transcription is not None else False
|
|
164
|
-
)
|
|
165
|
-
if repetition:
|
|
166
|
-
issues.append("repetition_detected")
|
|
167
|
-
|
|
168
|
-
# Loudness dip: reuse the verify-phase result when present; only run the windowed
|
|
169
|
-
# scan when the verify phase did not (meta.loudness_dip absent).
|
|
170
|
-
dip, dip_at = (
|
|
171
|
-
(bool(meta["loudness_dip"]), None) if "loudness_dip" in meta else detect_loudness_dip(wav)
|
|
172
|
-
)
|
|
173
|
-
if dip:
|
|
174
|
-
issues.append(f"loudness_dip:{f'{dip_at}s' if dip_at is not None else 'unknown'}")
|
|
175
|
-
|
|
176
162
|
# Duration anomaly
|
|
177
163
|
ratio_anomaly = duration > MAX_DURATION_RATIO * max_sec if max_sec > 0 else False
|
|
178
164
|
abs_anomaly = duration > max_sec + MAX_ABS_DIFF_SEC if max_sec > 0 else False
|
|
@@ -187,6 +173,27 @@ def audit_voice_segments(
|
|
|
187
173
|
f"duration_anomaly: expected {min_sec:.2f}s-{max_sec:.2f}s, got {duration:.2f}s"
|
|
188
174
|
)
|
|
189
175
|
|
|
176
|
+
# Repetition — transcription channel only, corroborated by duration anomaly (voice-gen
|
|
177
|
+
# qc.ts parity): the battery is an ASR/TTS-artifact detector, not a source-text lint.
|
|
178
|
+
# Source strings like version numbers ("1.1.1.") are legitimate copy and speak fine
|
|
179
|
+
# (dogfood 2026-09-18: a version string in the source tripped the word-run regex and
|
|
180
|
+
# condemned a 70-minute render that no regeneration could fix). A real TTS loop always
|
|
181
|
+
# inflates duration; a Whisper phantom loop over trailing silence does not.
|
|
182
|
+
repetition = detect_repetitions(transcription) if transcription is not None else False
|
|
183
|
+
if repetition and duration_anomaly:
|
|
184
|
+
# Bare token: pipeline.py's R5a gate matches issues by exact membership.
|
|
185
|
+
issues.append("repetition_detected")
|
|
186
|
+
|
|
187
|
+
# Loudness dip: reuse the verify-phase result when present; only run the windowed
|
|
188
|
+
# scan when the verify phase did not (meta.loudness_dip absent).
|
|
189
|
+
dip, dip_at = (
|
|
190
|
+
(bool(meta["loudness_dip"]), meta.get("dip_at"))
|
|
191
|
+
if "loudness_dip" in meta
|
|
192
|
+
else detect_loudness_dip(wav)
|
|
193
|
+
)
|
|
194
|
+
if dip:
|
|
195
|
+
issues.append(f"loudness_dip:{f'{dip_at}s' if dip_at is not None else 'unknown'}")
|
|
196
|
+
|
|
190
197
|
audits.append(
|
|
191
198
|
SegmentQualityAudit(
|
|
192
199
|
segment_index=index,
|
|
@@ -198,6 +205,7 @@ def audit_voice_segments(
|
|
|
198
205
|
repetition_detected=repetition,
|
|
199
206
|
duration_anomaly=duration_anomaly,
|
|
200
207
|
fidelity_score=fidelity,
|
|
208
|
+
verify_retries=int(meta.get("verify_retries", 0) or 0),
|
|
201
209
|
issues=issues,
|
|
202
210
|
)
|
|
203
211
|
)
|
|
@@ -21781,6 +21781,22 @@ var ResultSchema = exports_external.object({
|
|
|
21781
21781
|
error: exports_external.string().optional(),
|
|
21782
21782
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21783
21783
|
});
|
|
21784
|
+
var TargetOutcomeSchema = exports_external.object({
|
|
21785
|
+
target: exports_external.string(),
|
|
21786
|
+
ok: exports_external.boolean(),
|
|
21787
|
+
status: exports_external.enum(["published", "failed", "skipped"]),
|
|
21788
|
+
url: exports_external.string().optional(),
|
|
21789
|
+
id: exports_external.string().optional(),
|
|
21790
|
+
error: exports_external.string().optional(),
|
|
21791
|
+
durationMs: exports_external.number().optional(),
|
|
21792
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21793
|
+
});
|
|
21794
|
+
var AggregateResultSchema = exports_external.object({
|
|
21795
|
+
ok: exports_external.boolean(),
|
|
21796
|
+
summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
|
|
21797
|
+
targets: exports_external.array(TargetOutcomeSchema),
|
|
21798
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21799
|
+
});
|
|
21784
21800
|
var DocListSchema = exports_external.array(DocSchema);
|
|
21785
21801
|
var omniVoiceGenContentSchema = ContentSchema.extend({
|
|
21786
21802
|
format: exports_external.literal("audio"),
|
|
@@ -21809,14 +21825,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
|
|
|
21809
21825
|
// ../../packages/kk-core/src/manifest.ts
|
|
21810
21826
|
init_zod();
|
|
21811
21827
|
var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
|
|
21812
|
-
var
|
|
21828
|
+
var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
|
|
21829
|
+
var PluginManifestSchema = exports_external.looseObject({
|
|
21813
21830
|
name: exports_external.string().min(1),
|
|
21814
21831
|
kind: PluginKindSchema,
|
|
21815
21832
|
entry: exports_external.string().min(1),
|
|
21816
21833
|
version: exports_external.string().optional(),
|
|
21817
21834
|
description: exports_external.string().optional(),
|
|
21818
|
-
operations: exports_external.record(exports_external.string(),
|
|
21819
|
-
})
|
|
21835
|
+
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21836
|
+
});
|
|
21820
21837
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21821
21838
|
init_file_system_node();
|
|
21822
21839
|
init_config();
|
|
@@ -22249,16 +22266,22 @@ async function auditVoiceSegments(script, segmentWavs, segmentMetadata, client)
|
|
|
22249
22266
|
}
|
|
22250
22267
|
|
|
22251
22268
|
// ../../plugins/generations/voice-gen/src/voicebox-client.ts
|
|
22269
|
+
function resolveVoiceboxTimeoutMs() {
|
|
22270
|
+
const raw = process.env.VOICEBOX_TIMEOUT_MS;
|
|
22271
|
+
const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
22272
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 600000;
|
|
22273
|
+
}
|
|
22252
22274
|
function createVoiceboxClient(options = {}) {
|
|
22253
22275
|
const rawUrl = options.url || process.env.VOICEBOX_URL || "http://127.0.0.1:17493";
|
|
22254
22276
|
const url2 = rawUrl.replace(/\/+$/, "");
|
|
22255
22277
|
const customFetch = options.fetch ?? globalThis.fetch;
|
|
22256
22278
|
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
22279
|
+
const requestTimeoutMs = resolveVoiceboxTimeoutMs();
|
|
22257
22280
|
return {
|
|
22258
22281
|
url: url2,
|
|
22259
22282
|
async health() {
|
|
22260
22283
|
try {
|
|
22261
|
-
const res = await customFetch(`${url2}/health
|
|
22284
|
+
const res = await customFetch(`${url2}/health`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
22262
22285
|
if (!res.ok) {
|
|
22263
22286
|
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
22264
22287
|
}
|
|
@@ -22270,7 +22293,7 @@ function createVoiceboxClient(options = {}) {
|
|
|
22270
22293
|
async resolveProfile(nameOrId) {
|
|
22271
22294
|
let res;
|
|
22272
22295
|
try {
|
|
22273
|
-
res = await customFetch(`${url2}/profiles
|
|
22296
|
+
res = await customFetch(`${url2}/profiles`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
22274
22297
|
} catch (err) {
|
|
22275
22298
|
const reason = err instanceof Error ? err.message : String(err);
|
|
22276
22299
|
throw new Error(`Voicebox /profiles request failed at ${url2}: ${reason}`);
|
|
@@ -22303,7 +22326,8 @@ function createVoiceboxClient(options = {}) {
|
|
|
22303
22326
|
headers: {
|
|
22304
22327
|
"Content-Type": "application/json"
|
|
22305
22328
|
},
|
|
22306
|
-
body: JSON.stringify(body)
|
|
22329
|
+
body: JSON.stringify(body),
|
|
22330
|
+
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
22307
22331
|
});
|
|
22308
22332
|
} catch (err) {
|
|
22309
22333
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -22335,7 +22359,7 @@ function createVoiceboxClient(options = {}) {
|
|
|
22335
22359
|
while (true) {
|
|
22336
22360
|
let res;
|
|
22337
22361
|
try {
|
|
22338
|
-
res = await customFetch(`${url2}/history/${id}
|
|
22362
|
+
res = await customFetch(`${url2}/history/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
22339
22363
|
} catch (err) {
|
|
22340
22364
|
const reason = err instanceof Error ? err.message : String(err);
|
|
22341
22365
|
throw new Error(`Voicebox /history/${id} request failed at ${url2}: ${reason}`);
|
|
@@ -22369,7 +22393,7 @@ function createVoiceboxClient(options = {}) {
|
|
|
22369
22393
|
async downloadAudio(id) {
|
|
22370
22394
|
let res;
|
|
22371
22395
|
try {
|
|
22372
|
-
res = await customFetch(`${url2}/audio/${id}
|
|
22396
|
+
res = await customFetch(`${url2}/audio/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
22373
22397
|
} catch (err) {
|
|
22374
22398
|
const reason = err instanceof Error ? err.message : String(err);
|
|
22375
22399
|
throw new Error(`Voicebox /audio/${id} request failed at ${url2}: ${reason}`);
|
|
@@ -22394,7 +22418,8 @@ function createVoiceboxClient(options = {}) {
|
|
|
22394
22418
|
try {
|
|
22395
22419
|
res = await customFetch(`${url2}/transcribe`, {
|
|
22396
22420
|
method: "POST",
|
|
22397
|
-
body: formData
|
|
22421
|
+
body: formData,
|
|
22422
|
+
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
22398
22423
|
});
|
|
22399
22424
|
} catch (err) {
|
|
22400
22425
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -22423,7 +22448,7 @@ var POLL_MS = 500;
|
|
|
22423
22448
|
var LOG_PATH = "/tmp/voicebox-server.log";
|
|
22424
22449
|
async function probeVoiceboxHealth(url2, customFetch) {
|
|
22425
22450
|
try {
|
|
22426
|
-
return (await customFetch(`${url2}/health
|
|
22451
|
+
return (await customFetch(`${url2}/health`, { signal: AbortSignal.timeout(resolveVoiceboxTimeoutMs()) })).ok;
|
|
22427
22452
|
} catch {
|
|
22428
22453
|
return false;
|
|
22429
22454
|
}
|
|
@@ -23097,6 +23122,7 @@ export {
|
|
|
23097
23122
|
validateVoiceScript,
|
|
23098
23123
|
transcriptionFidelity,
|
|
23099
23124
|
transcodeWavToMp3,
|
|
23125
|
+
resolveVoiceboxTimeoutMs,
|
|
23100
23126
|
resolveInstruct,
|
|
23101
23127
|
resolveEffectsChain,
|
|
23102
23128
|
processGeneratorIO,
|
|
@@ -56,18 +56,30 @@ export interface VoiceboxClientOptions {
|
|
|
56
56
|
/**
|
|
57
57
|
* Creates a client for the Voicebox local REST API.
|
|
58
58
|
*/
|
|
59
|
+
/**
|
|
60
|
+
* Per-request timeout (ms): `VOICEBOX_TIMEOUT_MS` when set to a positive number, else 600 000.
|
|
61
|
+
* Voice generation is slow, so the default is generous — but every call must be bounded, because
|
|
62
|
+
* Bun's `fetch` has no overall request deadline without a `signal` (R5).
|
|
63
|
+
*/
|
|
64
|
+
export function resolveVoiceboxTimeoutMs(): number {
|
|
65
|
+
const raw = process.env.VOICEBOX_TIMEOUT_MS;
|
|
66
|
+
const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
67
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 600_000;
|
|
68
|
+
}
|
|
69
|
+
|
|
59
70
|
export function createVoiceboxClient(options: VoiceboxClientOptions = {}): VoiceboxClient {
|
|
60
71
|
const rawUrl = options.url || process.env.VOICEBOX_URL || 'http://127.0.0.1:17493';
|
|
61
72
|
const url = rawUrl.replace(/\/+$/, '');
|
|
62
73
|
const customFetch = options.fetch ?? globalThis.fetch;
|
|
63
74
|
const sleep = options.sleep ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
75
|
+
const requestTimeoutMs = resolveVoiceboxTimeoutMs();
|
|
64
76
|
|
|
65
77
|
return {
|
|
66
78
|
url,
|
|
67
79
|
|
|
68
80
|
async health(): Promise<void> {
|
|
69
81
|
try {
|
|
70
|
-
const res = await customFetch(`${url}/health
|
|
82
|
+
const res = await customFetch(`${url}/health`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
71
83
|
if (!res.ok) {
|
|
72
84
|
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
73
85
|
}
|
|
@@ -82,7 +94,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
|
|
|
82
94
|
async resolveProfile(nameOrId: string): Promise<VoiceboxProfile> {
|
|
83
95
|
let res: Response;
|
|
84
96
|
try {
|
|
85
|
-
res = await customFetch(`${url}/profiles
|
|
97
|
+
res = await customFetch(`${url}/profiles`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
86
98
|
} catch (err: unknown) {
|
|
87
99
|
const reason = err instanceof Error ? err.message : String(err);
|
|
88
100
|
throw new Error(`Voicebox /profiles request failed at ${url}: ${reason}`);
|
|
@@ -123,6 +135,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
|
|
|
123
135
|
'Content-Type': 'application/json',
|
|
124
136
|
},
|
|
125
137
|
body: JSON.stringify(body),
|
|
138
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
126
139
|
});
|
|
127
140
|
} catch (err: unknown) {
|
|
128
141
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -170,7 +183,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
|
|
|
170
183
|
while (true) {
|
|
171
184
|
let res: Response;
|
|
172
185
|
try {
|
|
173
|
-
res = await customFetch(`${url}/history/${id}
|
|
186
|
+
res = await customFetch(`${url}/history/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
174
187
|
} catch (err: unknown) {
|
|
175
188
|
const reason = err instanceof Error ? err.message : String(err);
|
|
176
189
|
throw new Error(`Voicebox /history/${id} request failed at ${url}: ${reason}`);
|
|
@@ -212,7 +225,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
|
|
|
212
225
|
async downloadAudio(id: string): Promise<Uint8Array> {
|
|
213
226
|
let res: Response;
|
|
214
227
|
try {
|
|
215
|
-
res = await customFetch(`${url}/audio/${id}
|
|
228
|
+
res = await customFetch(`${url}/audio/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
|
|
216
229
|
} catch (err: unknown) {
|
|
217
230
|
const reason = err instanceof Error ? err.message : String(err);
|
|
218
231
|
throw new Error(`Voicebox /audio/${id} request failed at ${url}: ${reason}`);
|
|
@@ -242,6 +255,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
|
|
|
242
255
|
res = await customFetch(`${url}/transcribe`, {
|
|
243
256
|
method: 'POST',
|
|
244
257
|
body: formData,
|
|
258
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
245
259
|
});
|
|
246
260
|
} catch (err: unknown) {
|
|
247
261
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -3,6 +3,7 @@ import { existsSync, openSync } from 'node:fs';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { echoError } from '@gobing-ai/ts-utils';
|
|
6
|
+
import { resolveVoiceboxTimeoutMs } from './voicebox-client';
|
|
6
7
|
|
|
7
8
|
/** Boot wait / poll cadence for a freshly spawned local server (Voicebox cold start ≈ 2-5s). */
|
|
8
9
|
const BOOT_WAIT_MS = 30_000;
|
|
@@ -23,7 +24,7 @@ export interface VoiceboxServerOptions {
|
|
|
23
24
|
|
|
24
25
|
async function probeVoiceboxHealth(url: string, customFetch: typeof fetch): Promise<boolean> {
|
|
25
26
|
try {
|
|
26
|
-
return (await customFetch(`${url}/health
|
|
27
|
+
return (await customFetch(`${url}/health`, { signal: AbortSignal.timeout(resolveVoiceboxTimeoutMs()) })).ok;
|
|
27
28
|
} catch {
|
|
28
29
|
return false;
|
|
29
30
|
}
|
|
@@ -21781,6 +21781,22 @@ var ResultSchema = exports_external.object({
|
|
|
21781
21781
|
error: exports_external.string().optional(),
|
|
21782
21782
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21783
21783
|
});
|
|
21784
|
+
var TargetOutcomeSchema = exports_external.object({
|
|
21785
|
+
target: exports_external.string(),
|
|
21786
|
+
ok: exports_external.boolean(),
|
|
21787
|
+
status: exports_external.enum(["published", "failed", "skipped"]),
|
|
21788
|
+
url: exports_external.string().optional(),
|
|
21789
|
+
id: exports_external.string().optional(),
|
|
21790
|
+
error: exports_external.string().optional(),
|
|
21791
|
+
durationMs: exports_external.number().optional(),
|
|
21792
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21793
|
+
});
|
|
21794
|
+
var AggregateResultSchema = exports_external.object({
|
|
21795
|
+
ok: exports_external.boolean(),
|
|
21796
|
+
summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
|
|
21797
|
+
targets: exports_external.array(TargetOutcomeSchema),
|
|
21798
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21799
|
+
});
|
|
21784
21800
|
var DocListSchema = exports_external.array(DocSchema);
|
|
21785
21801
|
var omniVoiceGenContentSchema = ContentSchema.extend({
|
|
21786
21802
|
format: exports_external.literal("audio"),
|
|
@@ -21809,14 +21825,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
|
|
|
21809
21825
|
// ../../packages/kk-core/src/manifest.ts
|
|
21810
21826
|
init_zod();
|
|
21811
21827
|
var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
|
|
21812
|
-
var
|
|
21828
|
+
var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
|
|
21829
|
+
var PluginManifestSchema = exports_external.looseObject({
|
|
21813
21830
|
name: exports_external.string().min(1),
|
|
21814
21831
|
kind: PluginKindSchema,
|
|
21815
21832
|
entry: exports_external.string().min(1),
|
|
21816
21833
|
version: exports_external.string().optional(),
|
|
21817
21834
|
description: exports_external.string().optional(),
|
|
21818
|
-
operations: exports_external.record(exports_external.string(),
|
|
21819
|
-
})
|
|
21835
|
+
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21836
|
+
});
|
|
21820
21837
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21821
21838
|
init_file_system_node();
|
|
21822
21839
|
init_config();
|
|
@@ -21911,6 +21928,7 @@ init_zod();
|
|
|
21911
21928
|
|
|
21912
21929
|
// ../../plugins/ingestions/aihot-ingest/src/client.ts
|
|
21913
21930
|
init_zod();
|
|
21931
|
+
var REQUEST_TIMEOUT_MS = 120000;
|
|
21914
21932
|
var AIHOT_BASE_URL = "https://aihot.virxact.com";
|
|
21915
21933
|
var DEFAULT_AIHOT_USER_AGENT = "aihot-ingest/1.0.0";
|
|
21916
21934
|
var AihotItemSchema = exports_external.object({
|
|
@@ -21996,7 +22014,8 @@ class AihotClient {
|
|
|
21996
22014
|
headers: {
|
|
21997
22015
|
Accept: "application/json",
|
|
21998
22016
|
"User-Agent": this.userAgent
|
|
21999
|
-
}
|
|
22017
|
+
},
|
|
22018
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
22000
22019
|
});
|
|
22001
22020
|
if (!res.ok) {
|
|
22002
22021
|
const errBody = (await res.text()).slice(0, 1000);
|
|
@@ -22019,7 +22038,8 @@ class AihotClient {
|
|
|
22019
22038
|
headers: {
|
|
22020
22039
|
Accept: "application/json",
|
|
22021
22040
|
"User-Agent": this.userAgent
|
|
22022
|
-
}
|
|
22041
|
+
},
|
|
22042
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
22023
22043
|
});
|
|
22024
22044
|
if (!res.ok) {
|
|
22025
22045
|
const errBody = (await res.text()).slice(0, 1000);
|
|
@@ -22086,7 +22106,7 @@ function mapAihotItemsToDocs(items) {
|
|
|
22086
22106
|
|
|
22087
22107
|
// ../../plugins/ingestions/aihot-ingest/src/rss.ts
|
|
22088
22108
|
import { createHash as createHash2 } from "crypto";
|
|
22089
|
-
var AIHOT_FEED_URL_DEFAULT = "https://
|
|
22109
|
+
var AIHOT_FEED_URL_DEFAULT = "https://arstechnica.com/ai/feed/";
|
|
22090
22110
|
function stripMarkup(raw) {
|
|
22091
22111
|
return raw.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, "$1").replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'|'/g, "'").replace(/\s+/g, " ").trim();
|
|
22092
22112
|
}
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
"kind": "ingestion",
|
|
4
4
|
"entry": "./dist/index.js",
|
|
5
5
|
"version": "1.0.0",
|
|
6
|
-
"description": "Ingests fresh AI news from an RSS feed (default
|
|
6
|
+
"description": "Ingests fresh AI news from an RSS feed (default Ars Technica AI, full text) into Doc[]; legacy aihot.virxact.com API behind AIHOT_SOURCE=api"
|
|
7
7
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { echoError } from '@gobing-ai/ts-utils';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
+
/** Per-request timeout (ms) for aihot HTTP calls — Bun's `fetch` has no default deadline (R5). */
|
|
5
|
+
const REQUEST_TIMEOUT_MS = 120_000;
|
|
6
|
+
|
|
4
7
|
export const AIHOT_BASE_URL = 'https://aihot.virxact.com';
|
|
5
8
|
export const DEFAULT_AIHOT_USER_AGENT = 'aihot-ingest/1.0.0';
|
|
6
9
|
|
|
@@ -123,6 +126,7 @@ export class AihotClient {
|
|
|
123
126
|
Accept: 'application/json',
|
|
124
127
|
'User-Agent': this.userAgent,
|
|
125
128
|
},
|
|
129
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
126
130
|
});
|
|
127
131
|
|
|
128
132
|
if (!res.ok) {
|
|
@@ -152,6 +156,7 @@ export class AihotClient {
|
|
|
152
156
|
Accept: 'application/json',
|
|
153
157
|
'User-Agent': this.userAgent,
|
|
154
158
|
},
|
|
159
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
155
160
|
});
|
|
156
161
|
|
|
157
162
|
if (!res.ok) {
|
|
@@ -15,8 +15,18 @@ import type { Doc } from '@gobing-ai/kk-core';
|
|
|
15
15
|
* still applies to feed items.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
/** Default fresh AI-news feed (RSS 2.0,
|
|
19
|
-
|
|
18
|
+
/** Default fresh AI-news feed (RSS 2.0, full text, reachable without auth).
|
|
19
|
+
*
|
|
20
|
+
* Why Ars Technica (2026-09-20, dogfood): the previous default (TechCrunch AI
|
|
21
|
+
* category feed) stopped shipping `content:encoded` — items now carry only
|
|
22
|
+
* 86–236-char `description` summaries. Every such body lands below the planner's
|
|
23
|
+
* STUB_BODY_FLOOR (300 chars), scores quality 1, and is auto-rejected at
|
|
24
|
+
* `qc_min_quality=2`, so the aihot leg contributed ~0 usable items (the
|
|
25
|
+
* 2026-09-20 episode collapsed to 3 items / 5m33s). The Ars Technica AI feed
|
|
26
|
+
* ships full `content:encoded` (≈900–1800 chars) on every item. The parser
|
|
27
|
+
* already prefers `content:encoded`, so only the URL changes.
|
|
28
|
+
*/
|
|
29
|
+
export const AIHOT_FEED_URL_DEFAULT = 'https://arstechnica.com/ai/feed/';
|
|
20
30
|
|
|
21
31
|
export type RssFetchLike = (url: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
22
32
|
|
|
@@ -21782,6 +21782,22 @@ var ResultSchema = exports_external.object({
|
|
|
21782
21782
|
error: exports_external.string().optional(),
|
|
21783
21783
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21784
21784
|
});
|
|
21785
|
+
var TargetOutcomeSchema = exports_external.object({
|
|
21786
|
+
target: exports_external.string(),
|
|
21787
|
+
ok: exports_external.boolean(),
|
|
21788
|
+
status: exports_external.enum(["published", "failed", "skipped"]),
|
|
21789
|
+
url: exports_external.string().optional(),
|
|
21790
|
+
id: exports_external.string().optional(),
|
|
21791
|
+
error: exports_external.string().optional(),
|
|
21792
|
+
durationMs: exports_external.number().optional(),
|
|
21793
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21794
|
+
});
|
|
21795
|
+
var AggregateResultSchema = exports_external.object({
|
|
21796
|
+
ok: exports_external.boolean(),
|
|
21797
|
+
summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
|
|
21798
|
+
targets: exports_external.array(TargetOutcomeSchema),
|
|
21799
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21800
|
+
});
|
|
21785
21801
|
var DocListSchema = exports_external.array(DocSchema);
|
|
21786
21802
|
var omniVoiceGenContentSchema = ContentSchema.extend({
|
|
21787
21803
|
format: exports_external.literal("audio"),
|
|
@@ -21810,14 +21826,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
|
|
|
21810
21826
|
// ../../packages/kk-core/src/manifest.ts
|
|
21811
21827
|
init_zod();
|
|
21812
21828
|
var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
|
|
21813
|
-
var
|
|
21829
|
+
var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
|
|
21830
|
+
var PluginManifestSchema = exports_external.looseObject({
|
|
21814
21831
|
name: exports_external.string().min(1),
|
|
21815
21832
|
kind: PluginKindSchema,
|
|
21816
21833
|
entry: exports_external.string().min(1),
|
|
21817
21834
|
version: exports_external.string().optional(),
|
|
21818
21835
|
description: exports_external.string().optional(),
|
|
21819
|
-
operations: exports_external.record(exports_external.string(),
|
|
21820
|
-
})
|
|
21836
|
+
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21837
|
+
});
|
|
21821
21838
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21822
21839
|
init_file_system_node();
|
|
21823
21840
|
init_config();
|
|
@@ -21783,6 +21783,22 @@ var ResultSchema = exports_external.object({
|
|
|
21783
21783
|
error: exports_external.string().optional(),
|
|
21784
21784
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21785
21785
|
});
|
|
21786
|
+
var TargetOutcomeSchema = exports_external.object({
|
|
21787
|
+
target: exports_external.string(),
|
|
21788
|
+
ok: exports_external.boolean(),
|
|
21789
|
+
status: exports_external.enum(["published", "failed", "skipped"]),
|
|
21790
|
+
url: exports_external.string().optional(),
|
|
21791
|
+
id: exports_external.string().optional(),
|
|
21792
|
+
error: exports_external.string().optional(),
|
|
21793
|
+
durationMs: exports_external.number().optional(),
|
|
21794
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21795
|
+
});
|
|
21796
|
+
var AggregateResultSchema = exports_external.object({
|
|
21797
|
+
ok: exports_external.boolean(),
|
|
21798
|
+
summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
|
|
21799
|
+
targets: exports_external.array(TargetOutcomeSchema),
|
|
21800
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21801
|
+
});
|
|
21786
21802
|
var DocListSchema = exports_external.array(DocSchema);
|
|
21787
21803
|
var omniVoiceGenContentSchema = ContentSchema.extend({
|
|
21788
21804
|
format: exports_external.literal("audio"),
|
|
@@ -21811,14 +21827,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
|
|
|
21811
21827
|
// ../../packages/kk-core/src/manifest.ts
|
|
21812
21828
|
init_zod();
|
|
21813
21829
|
var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
|
|
21814
|
-
var
|
|
21830
|
+
var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
|
|
21831
|
+
var PluginManifestSchema = exports_external.looseObject({
|
|
21815
21832
|
name: exports_external.string().min(1),
|
|
21816
21833
|
kind: PluginKindSchema,
|
|
21817
21834
|
entry: exports_external.string().min(1),
|
|
21818
21835
|
version: exports_external.string().optional(),
|
|
21819
21836
|
description: exports_external.string().optional(),
|
|
21820
|
-
operations: exports_external.record(exports_external.string(),
|
|
21821
|
-
})
|
|
21837
|
+
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21838
|
+
});
|
|
21822
21839
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21823
21840
|
init_file_system_node();
|
|
21824
21841
|
init_config();
|
|
@@ -21782,6 +21782,22 @@ var ResultSchema = exports_external.object({
|
|
|
21782
21782
|
error: exports_external.string().optional(),
|
|
21783
21783
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21784
21784
|
});
|
|
21785
|
+
var TargetOutcomeSchema = exports_external.object({
|
|
21786
|
+
target: exports_external.string(),
|
|
21787
|
+
ok: exports_external.boolean(),
|
|
21788
|
+
status: exports_external.enum(["published", "failed", "skipped"]),
|
|
21789
|
+
url: exports_external.string().optional(),
|
|
21790
|
+
id: exports_external.string().optional(),
|
|
21791
|
+
error: exports_external.string().optional(),
|
|
21792
|
+
durationMs: exports_external.number().optional(),
|
|
21793
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21794
|
+
});
|
|
21795
|
+
var AggregateResultSchema = exports_external.object({
|
|
21796
|
+
ok: exports_external.boolean(),
|
|
21797
|
+
summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
|
|
21798
|
+
targets: exports_external.array(TargetOutcomeSchema),
|
|
21799
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21800
|
+
});
|
|
21785
21801
|
var DocListSchema = exports_external.array(DocSchema);
|
|
21786
21802
|
var omniVoiceGenContentSchema = ContentSchema.extend({
|
|
21787
21803
|
format: exports_external.literal("audio"),
|
|
@@ -21810,14 +21826,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
|
|
|
21810
21826
|
// ../../packages/kk-core/src/manifest.ts
|
|
21811
21827
|
init_zod();
|
|
21812
21828
|
var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
|
|
21813
|
-
var
|
|
21829
|
+
var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
|
|
21830
|
+
var PluginManifestSchema = exports_external.looseObject({
|
|
21814
21831
|
name: exports_external.string().min(1),
|
|
21815
21832
|
kind: PluginKindSchema,
|
|
21816
21833
|
entry: exports_external.string().min(1),
|
|
21817
21834
|
version: exports_external.string().optional(),
|
|
21818
21835
|
description: exports_external.string().optional(),
|
|
21819
|
-
operations: exports_external.record(exports_external.string(),
|
|
21820
|
-
})
|
|
21836
|
+
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21837
|
+
});
|
|
21821
21838
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21822
21839
|
init_file_system_node();
|
|
21823
21840
|
init_config();
|
|
@@ -24042,6 +24059,7 @@ async function initializeLogger(options = {}) {
|
|
|
24042
24059
|
}
|
|
24043
24060
|
// ../../plugins/ingestions/web-search/src/index.ts
|
|
24044
24061
|
var log = getLogger2("kk.ingestion.web-search");
|
|
24062
|
+
var REQUEST_TIMEOUT_MS = 120000;
|
|
24045
24063
|
var FIXTURE_ENTRIES = [
|
|
24046
24064
|
{
|
|
24047
24065
|
sourceUri: "https://example.org/research/storm-overview",
|
|
@@ -24101,6 +24119,7 @@ async function searchFirecrawl(input, deps) {
|
|
|
24101
24119
|
"Content-Type": "application/json",
|
|
24102
24120
|
Authorization: `Bearer ${key}`
|
|
24103
24121
|
},
|
|
24122
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
24104
24123
|
body: JSON.stringify({
|
|
24105
24124
|
query: input.topic,
|
|
24106
24125
|
limit: input.maxResults,
|
|
@@ -8,6 +8,9 @@ import { echoError } from '@gobing-ai/ts-utils';
|
|
|
8
8
|
|
|
9
9
|
const log = getLogger('kk.ingestion.web-search');
|
|
10
10
|
|
|
11
|
+
/** Per-request timeout (ms) for the Firecrawl call — Bun's `fetch` has no default deadline (R5). */
|
|
12
|
+
const REQUEST_TIMEOUT_MS = 120_000;
|
|
13
|
+
|
|
11
14
|
/** Validated `--in` input per the 0054 contract (`topic` required; `maxResults`/`fixture` optional). */
|
|
12
15
|
interface InInput {
|
|
13
16
|
topic: string;
|
|
@@ -136,6 +139,7 @@ export async function searchFirecrawl(input: InInput, deps: SearchDeps): Promise
|
|
|
136
139
|
'Content-Type': 'application/json',
|
|
137
140
|
Authorization: `Bearer ${key}`,
|
|
138
141
|
},
|
|
142
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
139
143
|
body: JSON.stringify({
|
|
140
144
|
query: input.topic,
|
|
141
145
|
limit: input.maxResults,
|