Per-turn recall currently enters through the `agent/pre-step` waterfall, and
that hook can only return `messages`. The recall block therefore lands in
conversation history as a user message: the model reads its own memory as if a
user had said it. `systemPrompt.context` cannot fix this — it runs before the
turn text is known, so it can only render input-independent text.
The loop's `preStep` is the first seam holding BOTH the assembled prompt and
this turn's claimed messages. `lib/loop.js` subclasses the harness AgentLoop and
wraps that seam on the agent instance: a pure snapshot carrier message is moved
out of `messages` and into `assembly.sections`, so it becomes part of the system
prompt for that turn and never enters history.
Deliberately decoupled from the memory plugin: nothing imports it or matches its
name. Promotion keys off the shape every snapshot-style injector already uses
(`source.sections`, the same shape `dsh-time-context` emits).
Constraints honoured, each of which was a measured failure elsewhere:
- The promoted section carries `interpolate: false`; recalled text is free text
and may contain `{{...}}`, which the strict interpolator rejects.
- The subclass defines no constructor and no static `inject`. The parent already
registers the turnBoundary + inbox projections, calls `setFactory(this)`, and
declares `{{provider}}`/`{{model}}`; re-registering any of them throws at
startup.
- Only the instance's `preStep` is patched, never the prototype, which other
agents share.
Also wires the new peer: `scripts/link-dsh.sh` gains dsh-agent/dsh-agent-loop
(without them the package cannot resolve at test time), package.json declares
dsh-agent-loop as a peer and adds the new test file, and G2b's allowlist admits
dsh-agent-loop as a first-party harness package, with the reason recorded.
npm test: 247 pass, 0 fail.
56 lines
1.6 KiB
Bash
Executable File
56 lines
1.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Link the globally-installed dsh packages into node_modules.
|
|
#
|
|
# The plugin declares no dependency of its own, so nothing here is fetched from a
|
|
# registry. The dsh packages it *imports* at runtime are **peers**: they must come
|
|
# from the running harness, and npm will not install them for us. During
|
|
# development they live in
|
|
# /usr/lib/node_modules/@deepseek-ai (a global install), so this script wires them
|
|
# up by symlink instead of vendoring a copy that could drift from the harness.
|
|
#
|
|
# Usage: ./scripts/link-dsh.sh [global-modules-root]
|
|
set -euo pipefail
|
|
|
|
GLOBAL_ROOT="${1:-/usr/lib/node_modules}"
|
|
PEERS=(
|
|
cordis
|
|
dsh-agent
|
|
dsh-agent-loop
|
|
cosmokit
|
|
dsh-llm
|
|
dsh-session
|
|
dsh-scope
|
|
dsh-system-prompt
|
|
dsh-tools
|
|
dsh-util-values
|
|
cordis-plugin-loader
|
|
)
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
if [[ ! -d "$GLOBAL_ROOT/@deepseek-ai" ]]; then
|
|
echo "error: $GLOBAL_ROOT/@deepseek-ai not found — pass the root that holds the dsh install" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p node_modules/@deepseek-ai
|
|
for peer in "${PEERS[@]}"; do
|
|
src="$GLOBAL_ROOT/@deepseek-ai/$peer"
|
|
if [[ ! -d "$src" ]]; then
|
|
echo " skip $peer (not installed)"
|
|
continue
|
|
fi
|
|
ln -sfn "$src" "node_modules/@deepseek-ai/$peer"
|
|
echo " link $peer"
|
|
done
|
|
|
|
# js-yaml is a transitive dep of cordis-plugin-include; needed only by the
|
|
# loader integration test, and only when it is not resolvable already.
|
|
if [[ -d "$GLOBAL_ROOT/js-yaml" && ! -e node_modules/js-yaml ]]; then
|
|
ln -sfn "$GLOBAL_ROOT/js-yaml" node_modules/js-yaml
|
|
echo " link js-yaml"
|
|
fi
|
|
|
|
echo
|
|
echo "done. try: npm test && npm run check"
|