fix: rewrite tool-lab tests as pure functions (remove dead mount/FakeFs; fix import-type-as-value bug)
This commit is contained in:
@@ -35,8 +35,7 @@
|
||||
"node": ">=22.19"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"test": "vitest run"
|
||||
"build": "tsc -p tsconfig.json"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "^4.0.1",
|
||||
|
||||
@@ -1,79 +1,14 @@
|
||||
import { describe, expect, it, vi, afterEach } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import { FileSystem } from '@deepseek-ai/dsh-fs'
|
||||
import type { FsTarget, FsDirEntry, FsEditOutcome, FsEditRequest, FsInfo, FsPathInfo, FsWriteIntent, FsWriteOutcome, FsVersion, FsTargetKey } from '@deepseek-ai/dsh-fs'
|
||||
import * as ToolLab from '@deepseek-ai/dsh-tool-lab'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { runComfyImage, resolveImageArgs, buildWorkflow } from '@deepseek-ai/dsh-tool-lab/src/comfy.ts'
|
||||
import { runDoclingOcr } from '@deepseek-ai/dsh-tool-lab/src/docling.ts'
|
||||
import { runWhishTranscribe } from '@deepseek-ai/dsh-tool-lab/src/whish.ts'
|
||||
import type { SandboxExecutionPolicy, SandboxMode } from '@deepseek-ai/dsh-sandbox'
|
||||
|
||||
const testToolSignal = new AbortController().signal
|
||||
|
||||
/** In-memory fake ctx.fs backend for upload tools. */
|
||||
class FakeFs extends FileSystem {
|
||||
files = new Map<string, Uint8Array>()
|
||||
override async resolve(path: string): Promise<FsTarget> {
|
||||
return { targetKey: FsTargetKey(`key:${path}`), displayPath: `/abs/${path}` }
|
||||
}
|
||||
override processPath(target: FsTarget): string { return String(target.targetKey) }
|
||||
override fileUrl(target: FsTarget): string { return `file://${target.targetKey}` }
|
||||
override contains(parent: FsTarget, child: FsTarget): boolean {
|
||||
return child.targetKey === parent.targetKey || String(child.targetKey).startsWith(`${parent.targetKey}/`)
|
||||
}
|
||||
override async stat(): Promise<FsInfo | undefined> { return undefined }
|
||||
override async lstat(): Promise<FsPathInfo | undefined> { return undefined }
|
||||
override async readText(target: FsTarget): Promise<string> {
|
||||
return new TextDecoder().decode(this.files.get(target.targetKey) ?? new Uint8Array())
|
||||
}
|
||||
override async streamText(target: FsTarget): Promise<AsyncIterable<string>> {
|
||||
const text = await this.readText(target)
|
||||
return (async function* () { yield text })()
|
||||
}
|
||||
override async readBytes(target: FsTarget, _signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array> {
|
||||
const bytes = this.files.get(target.targetKey) ?? new Uint8Array()
|
||||
if (bytes.length > maxBytes) throw new Error('FS_TOO_LARGE')
|
||||
return bytes
|
||||
}
|
||||
override async listDir(): Promise<FsDirEntry[]> { return [] }
|
||||
override async writeText(target: FsTarget, content: string): Promise<FsWriteOutcome> {
|
||||
const before = this.files.get(target.targetKey) ?? null
|
||||
this.files.set(target.targetKey, new TextEncoder().encode(content))
|
||||
return { operation: before !== null ? 'update' : 'create', version: FsVersion('v2'), before, after: content }
|
||||
}
|
||||
override async editText(target: FsTarget, edit: FsEditRequest): Promise<FsEditOutcome> {
|
||||
const content = new TextDecoder().decode(this.files.get(target.targetKey) ?? new Uint8Array())
|
||||
const after = content.split(edit.oldString).join(edit.newString)
|
||||
this.files.set(target.targetKey, new TextEncoder().encode(after))
|
||||
return { version: FsVersion('v3'), before: content, after }
|
||||
}
|
||||
}
|
||||
|
||||
async function mount(opts: { files?: Record<string, Uint8Array> } = {}) {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(ToolRuntime)
|
||||
const fs = new FakeFs()
|
||||
if (opts.files) for (const [k, v] of Object.entries(opts.files)) fs.files.set(`key:${k}`, v)
|
||||
await ctx.plugin(fs, {})
|
||||
await ctx.plugin(ToolLab, {})
|
||||
let counter = 0
|
||||
const call = (name: string, args: unknown) => ctx.tools.execute({
|
||||
signal: testToolSignal,
|
||||
callId: CallId(`call-${++counter}`),
|
||||
name,
|
||||
arguments: args,
|
||||
})
|
||||
return { ctx, fs, call }
|
||||
}
|
||||
const pngBytes = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13])
|
||||
|
||||
function jsonResponse(body: unknown, { status = 200, headers }: { status?: number; headers?: Record<string, string> } = {}): Response {
|
||||
return new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json', ...headers } })
|
||||
}
|
||||
|
||||
const pngBytes = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13])
|
||||
|
||||
afterEach(() => { vi.unstubAllGlobals() })
|
||||
|
||||
describe('lab_generate_image (ComfyUI)', () => {
|
||||
@@ -86,8 +21,6 @@ describe('lab_generate_image (ComfyUI)', () => {
|
||||
if (url.includes('/history/p-1')) return jsonResponse({ 'p-1': { outputs: { '9': { images: [{ filename: 'dsh_00001_.png' }] } } } })
|
||||
throw new Error(`unexpected fetch ${url}`)
|
||||
}))
|
||||
const { fs } = await mountTarget({ files: { 'x.png': pngBytes } })
|
||||
void fs
|
||||
|
||||
const out = await runComfyImage('http://192.168.31.240:8188', resolveImageArgs({ prompt: 'a cat' }), undefined, 30_000)
|
||||
expect(out).toBe('http://192.168.31.240:8188/view?filename=dsh_00001_.png&subfolder=&type=output')
|
||||
@@ -154,9 +87,4 @@ describe('lab_transcribe_audio (Whishper)', () => {
|
||||
await expect(runWhishTranscribe('http://x', new Uint8Array(), 'a.wav', undefined, undefined, undefined, 30_000))
|
||||
.rejects.toThrow(/no id/)
|
||||
})
|
||||
})
|
||||
|
||||
// keep imports referenced for the fake implementation; these types come from
|
||||
// @deepseek-ai/dsh-fs and are used by FakeFs above.
|
||||
type _ = SandboxExecutionPolicy | SandboxMode
|
||||
export { FakeFs }
|
||||
})
|
||||
Reference in New Issue
Block a user