feat: use OpenClaw sub-agent for slow detect commands, fix keyword generation
register-skill-release / register (push) Failing after 1m36s
Details
register-skill-release / register (push) Failing after 1m36s
Details
- SKILL.md: detect/detect-and-search now spawned via sessions_spawn (non-blocking); search/session run inline - product-detector.ts: replace sequential chunk loop with worker-pool concurrency (withConcurrency) so all frames dispatch immediately up to the limit - index.ts: fix generateChineseKeyword prompt to name the container/organizer object, not the items it holds (e.g. 鞋架 not 鞋) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9f381f9bab
commit
778a51ad45
30
SKILL.md
30
SKILL.md
|
|
@ -86,9 +86,29 @@ VISION_API_BASE=http://localhost:11434/v1
|
|||
VISION_MODEL=llava:13b
|
||||
```
|
||||
|
||||
## Rules — MUST follow
|
||||
## Execution rules
|
||||
|
||||
1. **Execute only, do not reason about internals.** Run the CLI and return the output.
|
||||
2. **No fallback strategies.** Report errors as-is; do NOT try alternative approaches.
|
||||
3. **No retry loops.** If detection or search fails, report the failure.
|
||||
4. **Trust the tool's output.** The CLI handles session management and error formatting internally.
|
||||
### For `detect` and `detect-and-search` (slow — use sub-agent)
|
||||
|
||||
Spawn a sub-agent via `sessions_spawn`. Do **not** run the command directly.
|
||||
|
||||
```
|
||||
sessions_spawn(
|
||||
task: "Run this command and return the raw JSON output:\n\nbun dist/run.js <full command here>\n\nCopy the entire JSON output as your reply.",
|
||||
label: "video-product-snapshot",
|
||||
runTimeoutSeconds: 300,
|
||||
)
|
||||
```
|
||||
|
||||
- Announce immediately that processing has started and share the `runId`.
|
||||
- Wait for the sub-agent announcement, then parse and format the result for the user.
|
||||
|
||||
### For `search` and `session` (fast — run directly)
|
||||
|
||||
Run the CLI command inline, no sub-agent needed.
|
||||
|
||||
### General rules
|
||||
|
||||
1. **No fallback strategies.** Report errors as-is; do NOT try alternative approaches.
|
||||
2. **No retry loops.** If detection or search fails, report the failure.
|
||||
3. **Trust the tool's output.** The CLI handles session management and error formatting internally.
|
||||
|
|
|
|||
|
|
@ -198,10 +198,12 @@ async function generateChineseKeyword(description: string, visionConfig: VisionC
|
|||
model,
|
||||
prompt: `You are generating a 1688.com (Chinese B2B wholesale) product search keyword.
|
||||
Rules:
|
||||
- Output ONLY 2-4 Chinese words — the product category + 1-2 key material/feature words
|
||||
- Output ONLY 2-4 Chinese words — the product OBJECT TYPE + 1-2 key material/feature words
|
||||
- CRITICAL: If the product is a container, organizer, rack, shelf, bag, box, or holder, the keyword MUST name THAT object — NOT the items it holds.
|
||||
Examples: shoe rack → "金属鞋架", cable organizer → "理线器", storage shelf → "收纳架", toolbox → "工具箱"
|
||||
- Use common Chinese commerce terms, NOT a literal translation
|
||||
- No English, no punctuation, no explanation
|
||||
- Short broad terms work better than long specific phrases (e.g. "金属鞋架" not "黑色Z型金属网格鞋架")
|
||||
- Short broad terms work better than long specific phrases
|
||||
|
||||
Product description: ${description}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,23 +135,35 @@ export async function cropProduct(
|
|||
return outputPath;
|
||||
}
|
||||
|
||||
async function withConcurrency<T>(
|
||||
tasks: (() => Promise<T>)[],
|
||||
limit: number,
|
||||
): Promise<T[]> {
|
||||
const results: T[] = new Array(tasks.length);
|
||||
let next = 0;
|
||||
async function worker() {
|
||||
while (next < tasks.length) {
|
||||
const i = next++;
|
||||
results[i] = await tasks[i]();
|
||||
}
|
||||
}
|
||||
await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, worker));
|
||||
return results;
|
||||
}
|
||||
|
||||
export async function detectProductFrames(
|
||||
frames: ExtractedFrame[],
|
||||
minConfidence: number,
|
||||
concurrency: number = 5,
|
||||
concurrency: number = 10,
|
||||
visionConfig: VisionConfig,
|
||||
): Promise<ProductFrame[]> {
|
||||
const model = createVisionModel(visionConfig);
|
||||
|
||||
// Pass 1: parallel filter — discard junk frames
|
||||
const keepFlags: boolean[] = [];
|
||||
for (let i = 0; i < frames.length; i += concurrency) {
|
||||
const chunk = frames.slice(i, i + concurrency);
|
||||
const flags = await Promise.all(
|
||||
chunk.map((f) => filterFrame(f, model).catch(() => false))
|
||||
// Pass 1: all frames in parallel, bounded by concurrency
|
||||
const keepFlags = await withConcurrency(
|
||||
frames.map((f) => () => filterFrame(f, model).catch(() => false)),
|
||||
concurrency,
|
||||
);
|
||||
keepFlags.push(...flags);
|
||||
}
|
||||
|
||||
const candidates = frames.filter((_, i) => keepFlags[i]);
|
||||
if (candidates.length === 0) return [];
|
||||
|
|
|
|||
Loading…
Reference in New Issue