Commit Graph
10107 Commits
Author SHA1 Message Date
Yichen Jiang b77fb9036c refactor(agent-presets,web): copy-only preset authoring with a path to the files
The web YAML editor is gone. agentPreset.write (arbitrary composition
text) became agentPreset.copy { from, agentPreset, name? }: a host-side
whole-directory copy of ids the host resolves itself — symlinks
dereferenced, modes re-tightened to owner-only with owner-execute kept,
metadata rewritten to keep the source's description but never its name or
roster order. No composition text or path crosses the wire in either
authoring direction, and the entryListSchema/!!js concern dissolves with
assertComposition itself.

The settings section becomes: a read-only viewer over shipped
compositions, a copy dialog (id + optional display name) as the only
create entry, delete for custom rows, and a location action leading into
the preset's own files — agentPreset.openDocument { agentPreset } resolves
the directory host-side and opens it natively, or answers
{ opened: false, path } for the row to show as text where the deployment
has no desktop. agentPreset.list reports hasDocument beside authorable;
the gateway's nativeOpen config pins the capability where
canOpenNativePath platform detection would mislead. The privileged set is
now read/copy/openDocument/remove.

With files as the only composition editor, standing mounts grew
stamp-keyed generations: ensureStanding compares the composition file's
mtime+size and starts the next generation for later sessions, while every
joined session keeps the generation it runs on.

New keyless web lane (agent-preset-authoring, overlay pins
nativeOpen: false so goldens render one branch on every platform) drives
view/copy/reveal/delete end to end; the real-composition CLI e2e switches
to copy semantics.
2026-08-08 22:35:26 +08:00
Yichen Jiang 2cea99409f test(web): re-record goldens with the header preset label now rendering live
20 files, each +2 lines: the label icon and 标准模式 in the banner — the DOM
the label fix makes appear for sessions created in-tab, which these goldens
recorded the absence of.
2026-08-08 20:34:03 +08:00
Yichen Jiang 66e9b01fbd fix(tools,client): chain-mode resolution and a live preset label
modeFor read only the exact scope's layer, so a `code`-preset session
advertised the native catalog: the mode is declared on the preset's STANDING
scope, and the agent only parents to it. Nearest scope wins along the chain —
the mode decides what the model SEES, which is the class of fact the chain
inherits. Caught live (the model politely computed with bash and said
run_code was not in its list); the chain test pins it.

The client half of the label fix: the create echo and the session-added
frame's agentPreset now reach the session list (newest wins in the upsert —
every producer of the field reports the CURRENT composition), and a confirmed
blank-session switch publishes through the new ISessions.noteAgentPreset, so
the header label moves with the composition instead of waiting for a reload.
2026-08-08 20:19:00 +08:00
Yichen Jiang 3926e95c61 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring 2026-08-08 20:16:58 +08:00
Yichen Jiang c578ededa1 Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui 2026-08-08 20:16:58 +08:00
Yichen Jiang 132debb5fe fix(apiproxy): echo the resolved agent preset on create and session-added
session.create's reply named only the id, and the session-added frame's
agentPreset — which the server already derives via sessionListFields — was
stripped by the wire schema it never joined. A client therefore could not
label a session it just created (or learned live) until the next full list
refresh: the header's preset label rendered nothing for exactly the sessions
made in this tab. The create reply is the commit point that knows the
RESOLVED composition (a caller that named none gets the default the header
recorded), so both carriers now say it.
2026-08-08 20:16:50 +08:00
Yichen Jiang cacc8fbca7 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
Authoring meets standing mounts: write() and remove() drop the standing
pointer so the NEXT session composes the edited roster, while every session
already joined keeps the generation it runs on — a superseded generation is
never disposed while the process lives. The settings-dialog golden re-records
with this layer's Agent Preset nav entry, which the incoming layer-3 record
had overwritten.
2026-08-08 19:09:32 +08:00
Yichen Jiang 01bd8ecefe Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui
recompose becomes a parent re-link: the new preset's standing mount is
ensured BEFORE the link moves, so a failed switch leaves the agent exactly as
it was — the unmount-then-restore dance (and unmountPresetFor with it) is
gone, and the restore-failure test now asserts the agent KEEPS its tools with
the source directory deleted, because the standing mount is not the file.
2026-08-08 18:52:45 +08:00
Yichen Jiang 46649858f6 Merge branch 'stack/agent-profiles-1-seam' into stack/agent-profiles-3-wire
Rewires this layer onto the standing-mount model:

- serviceForAgent roots its search at the agent's standing mount (parent
  scope key → live mount fiber) — the composition no longer lives under the
  agent's own fiber, and two agents on one preset now address ONE instance,
  which the sharing test asserts instead of distinctness.
- viewFor/historyPage take a registry view SCOPE. A live agent is that scope;
  a cold read uses the recorded preset's standing key via standingKeyFor —
  composing plugins but starting no agent, session, or turn. A header without
  a preset (a pre-roster log) renders through the DEFAULT preset's standing
  layer; an unusable preset degrades the read to generic cards, never fails
  it. This turns produced-files and chat-scroll green structurally, with the
  token counts untouched (no resume, so the projections fold stays detached).
- The detached projections baseline now includes every standing unit's key at
  its empty fold (todos: null): the standing mount registers units
  deterministically, which is what makes the client's "omitted key =
  capability absence → clear" rule safe again. seeded-history's contract test
  asserts the new shape.
- The standard preset's realm preamble no longer claims a shared label pools
  instances — provide() throws on the second registration under one realm
  symbol; labels join REALMS.
2026-08-08 18:41:07 +08:00
Yichen Jiang d770fb21cc docs(scope,agent-presets): standing-mount model, parent chain, and the Agent Note 2026-08-08 18:08:20 +08:00
Yichen Jiang e18aa2745c refactor(scope,agent-presets): per-preset standing mounts over a scope parent chain
A preset is now ONE composition per process, not one per session. The roster
mounts it once under a synthetic standing scope; each agent joins by having
its scope key parented to the mount's. Two mechanisms in dsh-scope carry the
whole change: registration views walk the parent chain (global → preset →
agent, nearest shadowing farthest — ScopedLayers.chainLayers), and scoped
event dispatch admits a listener tagged with an ancestor of the carrier key,
which is what lets a standing composition's plan/compaction/token listeners
observe each agent composed under it while a sibling preset's stay deaf.

The preset plugins already key their state by Session/Agent — they predate
presets and were written for the shared world — so sharing one instance is a
return to their design, not a rewrite. Preset ymls are unchanged: one mount
per preset means one Entry per preset, whose entry-local realms keep two
presets' services apart exactly as they kept two sessions' apart before.

The standing scope hangs off the service's UNTRACED context (selfCtx): a
method invoked through the traceable proxy sees this.ctx rebound to the
caller and carrying its shadow, and a subtree minted from that resolves every
service through the shadow's fiber instead of each entry's own inject store —
preset rows then fail on the very services they declare.

A standing mount survives its agents deliberately. The composition a running
session joined must outlive the file changing or disappearing underneath it;
reclamation happens at whole-tree teardown, and file edits reach only future
generations (the authoring layer swaps the pointer, never disposes a joined
generation).
2026-08-08 17:51:49 +08:00
Yichen Jiang 65730f2aef fix(agent-presets): keep the goal service on the host plane in the other presets
`cordis` and `code` are full copies of `standard`, so each carried its own
copy of the goals group the Gateway cannot reach through. Same change, same
reason.
2026-08-08 15:56:22 +08:00
Yichen Jiang e52dd048f9 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
# Conflicts:
#	packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
2026-08-08 15:54:27 +08:00
Yichen Jiang 5e892aa6dc Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui
# Conflicts:
#	packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
2026-08-08 15:54:16 +08:00
Yichen Jiang a21644af59 fix(web-app,agent-presets): keep the goal service on the host plane
The Gateway serves the goal domain as Remote endpoints, and a Remote method
picks its receiver Service from a generated descriptor — `clear(agent, ref)`
takes its agent as a PARAMETER, so the invocation is direct and the receiver
resolves on the host. Behind the preset's entry-local realm there was nothing
to resolve, and every browser goal call answered `service-unavailable`: the
composer's Clear goal button left the bar on screen.

That is the `bash-env` criterion read from the other side. Injection is not the
only host relationship a Service can have; being READ from a host row is one
too. The registry is keyed by session, so one host instance serves every
session exactly as it did before presets. The preset keeps the model-facing
tool, which is the choice a preset is for.

Also reverts the cold-transcript presenter resolve: resuming an agent to reach
its presenters made the context meter drop its cache and token counts on every
cold-opened session, trading one silent degradation for another. The card
degradation it addressed is diagnosed and still open.
2026-08-08 15:53:39 +08:00
Yichen Jiang 61e7a93a66 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
# Conflicts:
#	packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
2026-08-08 15:29:22 +08:00
Yichen Jiang 43b2673b69 Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui
# Conflicts:
#	packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
2026-08-08 15:28:41 +08:00
Yichen Jiang 1c80023b12 fix(apiproxy): give a cold transcript read the agent its presenters live in
A preset registers its tools into the agent's OWN layer, so `session.history`
served while no agent exists found no presenter at all and every card degraded
to the generic renderer — silently, because a viewless entry is also what a
tool with no presenter produces. The web client opens a session by reading its
transcript, so this was the ordinary path, not an edge: the write row lost its
diff card, and with it the `locations` the produced-files row derives from.

The read now resolves the agent through the same deduplicated resume every
other session method takes, but only when a roster is composed: a deployment
without presets keeps its tools on the host layer, which needs no agent to
address, and keeps the storage-only read unchanged. A resolution failure stays
a successful read.
2026-08-08 15:27:57 +08:00
Yichen Jiang a06df4aa41 Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
The composer's preset seat stays removed here — this layer moved it to the
hero chip and the session-header action — so only the model seat takes the
`modelSeatLocked` narrowing master introduced.

Conflicts:
	apps/web/tests/snapshots/*/*.expected.md
	packages/client/connection/README.md
	packages/client/connection/README.zh.md
	packages/client/ui-conversation/src/client/skeleton/InputBar.tsx
	packages/host/apiproxy/src/fetch/client.ts
2026-08-08 15:09:37 +08:00
Yichen Jiang beec364e04 Merge branch 'stack/agent-profiles-3-wire' into stack/agent-profiles-5-web-ui
The Client API carrier's `agentPresets` member was the one member of its class
without an `IApiClient[...]` annotation. Inferring it inlined `AgentPresetEntry`
into the emitted declaration by the specifier TS picks — the host `index.ts` —
dragging the whole gateway, and with it the host `Context` merges, into every
Client program importing the carrier. Annotated like its siblings.

`ApiRemoteAgentOptions.setup` now takes the inspected session rather than its
header alone: this layer resolves a resumed session's preset from the LOG,
because a session that switched while blank ran its turns under the newer
composition and the header is written once at creation.

Conflicts:
	apps/web/tests/snapshots/*/*.expected.md
	packages/client/ui-conversation/src/client/skeleton/InputBar.tsx
	packages/host/apiproxy/src/api-proxy.ts
	scripts/doc-budgets.manifest.json
2026-08-08 15:00:31 +08:00
Yichen Jiang c5ca12eabd Merge branch 'stack/agent-profiles-1-seam' into stack/agent-profiles-3-wire
master extracted this layer's inline cold-resume resolver into
@deepseek-ai/dsh-api-remotes, whose `setup` was a fixed AgentSetup. A resumed
session composes the preset ITS header recorded, so the option becomes a
function of that header; the resolver builds the setup before the published
re-checks so those stay adjacent to `resume`.

Conflicts:
	docs/cordis-catalog/services.md
	docs/module-graph.md
	packages/host/apiproxy/package.json
	packages/host/apiproxy/src/api-proxy.ts
	pnpm-lock.yaml
2026-08-08 14:26:38 +08:00
Yichen Jiang 2afdc68fab chore(docs): regenerate the graphs and re-record the pairings after the master merge 2026-08-08 14:04:53 +08:00
Yichen Jiang f517d29723 Merge remote-tracking branch 'origin/master' into stack/agent-profiles-1-seam
# Conflicts:
#	docs/capability-seams.md
#	docs/event-producer-consumer.md
#	packages/README.i18n.yaml
#	packages/ui/app-boot/README.i18n.yaml
#	packages/ui/app-boot/src/index.ts
#	scripts/doc-budgets.manifest.json
2026-08-08 14:00:34 +08:00
imccyu 0284e9c0b6 Merge pull request #1997 from deepseek-harness/feat/tsbuild2
build: order Host-generated Remote contracts before Client compilation
2026-08-08 12:53:01 +08:00
imccyu 8fc9032d71 test: refresh translation prompt snapshot 2026-08-08 12:36:50 +08:00
imccyu 863abcb427 build: enforce split project reference faces 2026-08-08 12:25:41 +08:00
imccyu d85d0806cd fix(build): align Client build metadata 2026-08-08 12:02:58 +08:00
imccyu 2a7c1175be fix(docs): keep doc typecheck on Host sources 2026-08-08 11:52:18 +08:00
Yichen Jiang 5cf5e0cb76 fix(agent-presets,connection): reclaim a deleted default, unpin a fence beside an open gate
Deleting the preset a user default names left the setting pointed at an id
nothing will ever supply again, and every session created without an explicit
pick then failed to start — the delete dialog called it 'new sessions cannot
select it', which understates a hard creation error. `remove` now clears the
user layer when it named the preset just deleted, exposing the deployment's own
default underneath. Storing a default that does not exist YET stays deliberate:
the roster is a live directory, so a name absent now may exist by the time a
session asks, and `resolve` still reports that case.

`agentPreset.select` also leaves the loopback set. It was pinned as a real
escalation — one preset mounts the toolset that edits the live runtime — but
`session.create` already takes an `agentPreset`, so pinning only the switch left
the same capability one method over. The deeper reason is that the capability is
not the preset's to grant: the deployment's own default already carries `bash`
and the filesystem tools, so any caller that may start a session at all can
already run commands as this process. `read`/`write`/`remove` stay pinned on
their own footing — those touch files, not sessions.
2026-08-08 11:41:47 +08:00
imccyu 8865548ee2 docs: explain generated Remote build order 2026-08-08 04:20:39 +08:00
imccyu 9c3d5725a5 build: order Host and Client compilation faces 2026-08-08 04:20:39 +08:00
Tianyi Cui 8158a0e63a Merge pull request #1979 from deepseek-harness/worktree/derive-compaction-replay-1971
test(snapshot): derive compaction replay from persisted summaries
2026-08-08 01:44:11 +08:00
Tianyi Cui e46b082fee test(snapshot): derive compaction replay from logs 2026-08-08 01:32:27 +08:00
Tianyi Cui a29a0a4773 Merge pull request #1547 from deepseek-harness/claude/unified-environment-credentials-c8841a
feat(config): rank every configuration source and bound what a discovered file may set
2026-08-08 00:43:42 +08:00
Tianyi Cui 510976351c test(telemetry): restore expression-tag coverage 2026-08-08 00:34:42 +08:00
Tianyi Cui b166b837d8 Merge origin/master at bc7849b97b 2026-08-07 23:57:47 +08:00
Tianyi Cui f00f45e3f9 Merge origin/master at f1402327fa 2026-08-07 23:57:23 +08:00
Tianyi Cui 698d65de2d Merge pull request #1965 from deepseek-harness/worktree/archive-agent-notes-aggressive-20260807
docs(notes): aggressively archive low-value records
2026-08-07 23:53:34 +08:00
Tianyi Cui 8315bfdc1f fix(notes): address archive review findings 2026-08-07 23:45:28 +08:00
Tianyi Cui 62ae990c27 cleanup(config): consolidate source ownership rationale 2026-08-07 23:43:15 +08:00
Tianyi Cui b5fbcaccf8 cleanup(config): localize bootstrap policy to app boot 2026-08-07 23:37:53 +08:00
Tianyi Cui d0e052dd83 cleanup(environment): keep one lookup order 2026-08-07 23:33:11 +08:00
Tianyi Cui 2c532f3b2c cleanup(environment): remove unused layer inventory 2026-08-07 23:30:03 +08:00
Tianyi Cui 95366f6197 fix(cli): parse commands before loading environment 2026-08-07 23:28:17 +08:00
Tianyi Cui 4ee93f7944 fix(config): cover shipped bundle source ownership 2026-08-07 23:26:39 +08:00
Tianyi Cui e901d9fcca Merge pull request #1785 from deepseek-harness/fix/update-explore-unknown-copy
fix(ui): update hero headline copy
2026-08-07 23:13:37 +08:00
Tianyi Cui 1c23f196fe fix(ui): use official hero title casing 2026-08-07 23:05:55 +08:00
Tianyi Cui 356ded2ca7 Merge branch 'master' into worktree/archive-agent-notes-aggressive-20260807 2026-08-07 22:57:51 +08:00
Tianyi Cui 06a449b38f Merge pull request #1550 from deepseek-harness/worktree/pr-to-issue-lifecycle
fix(infra): advance resolving Issue status from PRs
2026-08-07 22:53:44 +08:00
Tianyi Cui db0133b4c7 docs(notes): archive low-value records 2026-08-07 22:52:19 +08:00