Merge remote-tracking branch 'origin/master' into pr-265
# Conflicts: # docs/config-catalog.md # docs/cordis-catalog/services.md # docs/rfc/INDEX.md # examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/skill-load/session.jsonl # examples/acp-agent/tests/snapshots/text-turn/session.jsonl # examples/sandbox-acp-agent/tests/snapshots/escalation-approved/session.jsonl # examples/sandbox-acp-agent/tests/snapshots/escalation-rejected/session.jsonl # packages/core/agent-loop/README.md # packages/core/agent-loop/src/loop.ts # packages/core/tools/README.md # packages/core/tools/src/index.ts # packages/core/tools/src/schema.ts # packages/ui/acp/src/index.ts # packages/ui/stdio-agent/README.md
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
/**
|
||||
* Integration: the real fetch backend (`dsh-web-fetch-local`) + a real search
|
||||
* provider (`dsh-web-search-exa`) + the real seam (`dsh-web`) + the model tool
|
||||
* (`dsh-tool-web`) + the tool-call timeout policy (`dsh-timeout-policy`),
|
||||
* exercised through `ctx.tools.execute()` — nothing bypasses the tool registry.
|
||||
* Fetch hits a real loopback HTTP server (verifying the WORLD); search runs the
|
||||
* real Exa provider over a stubbed global `fetch` (the network is the one
|
||||
* boundary we mock).
|
||||
* Integration: the real fetch backend (`dsh-web-fetch-local`) + a real search provider
|
||||
* (`dsh-web-search-exa`) + the real seam (`dsh-web`) + the model tool (`dsh-tool-web`) + the
|
||||
* tool-call timeout policy (`dsh-timeout-policy`), exercised through `ctx.tools.execute()` —
|
||||
* nothing bypasses the tool registry. Fetch verifies world effects against loopback HTTP; search
|
||||
* uses the real Exa provider with only its network boundary stubbed.
|
||||
*/
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
@@ -159,10 +157,9 @@ describe('tool-call timeout returns TOOL_TIMEOUT (deadline wins over a slow fetc
|
||||
})
|
||||
|
||||
it('the provider backstop still protects a DIRECT ctx.web.fetch() call (no tool-call policy in that path)', async () => {
|
||||
// A direct seam caller does not go through tools/execute, so the tool-call
|
||||
// policy never applies; the provider's OWN timeout is the only budget. A
|
||||
// short per-request hint proves the provider backstop is intact and classifies
|
||||
// as WEB_FETCH_TIMEOUT (the provider-owned code), never TOOL_TIMEOUT.
|
||||
// A direct seam caller does not go through tools/execute, so the tool-call policy never
|
||||
// applies; the provider's own timeout is the only budget. A short request hint must therefore
|
||||
// produce provider-owned `WEB_FETCH_TIMEOUT`, never `TOOL_TIMEOUT`.
|
||||
const err = await tctx.web.fetch({ url: slowBase, timeoutMs: 50 }).then(
|
||||
() => undefined,
|
||||
(e: unknown) => e as { code?: string },
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
/**
|
||||
* Real-load-path guard for @deepseek-ai/dsh-tool-web. `tool-web` is a NAMESPACE
|
||||
* plugin with `inject` — so a stray `export default apply` would make the cordis
|
||||
* Loader's `unwrapExports` (`exports.default ?? exports`) collapse the module to
|
||||
* the bare `apply` function, DROPPING `inject`. The plugin would then read
|
||||
* `ctx.web` without having injected it and throw `cannot get property … without
|
||||
* inject` the moment it loads (postmortem 0001).
|
||||
*
|
||||
* A hand-built `ctx.plugin({ apply, inject })` mount CANNOT catch that — it
|
||||
* bypasses `unwrapExports`. So this test unwraps the module through the REAL
|
||||
* `Loader.prototype.unwrapExports` and mounts the result over `ctx.web`,
|
||||
* exercising the exact path the Loader uses. Prove the guard bites: add
|
||||
* `export default apply` to `src/index.ts`, watch this go red, revert.
|
||||
* Real Loader-path guard for an injected namespace plugin. A default export would make
|
||||
* `unwrapExports` collapse the namespace and drop `inject`, causing access to `ctx.web` to fail.
|
||||
* Hand-built mounting bypasses that path, so this test unwraps through the real Loader first; see
|
||||
* postmortem 0001.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
@@ -41,7 +33,7 @@ describe('dsh-tool-web real-load-path guard', () => {
|
||||
|
||||
const loader = Object.create(Loader.prototype) as Loader
|
||||
const unwrapped = loader.unwrapExports(toolWeb) as Parameters<Context['plugin']>[0]
|
||||
// A collapsed export shape (dropped inject) would throw "without inject" here.
|
||||
// Mounting the collapsed shape would throw for missing injection here.
|
||||
const fiber = await ctx.plugin(unwrapped)
|
||||
expect(ctx.tools.schemas().map(s => s.name)).toEqual(expect.arrayContaining(['web_search', 'web_fetch']))
|
||||
await fiber.dispose()
|
||||
|
||||
Reference in New Issue
Block a user