Просмотр исходного кода

Merge branch 'codex/simp-ui-identity-residue' into codex/simp-hide-concrete-agent-loop

Tianyi Cui 2 месяцев назад
Родитель
Сommit
fe132270a1

+ 1 - 0
packages/sdk/create-sdk/tests/create.spec.ts

@@ -257,6 +257,7 @@ describe('CreateWizard and scaffolder', () => {
     expect(index).toContain('SdkBootContext')
     expect(index).toContain('ctx.agents.create')
     expect(index).toContain('agentOptions: { model: "deepseek-v4-flash" }')
+    expect(index).not.toContain('AgentId')
     const tsconfig = parseGeneratedTsConfig(await readFile(join(target, 'tsconfig.base.json'), 'utf8'))
     const manifest = parseGeneratedPackageManifest(await readFile(join(target, 'package.json'), 'utf8'))
     expect(tsconfig.compilerOptions.types).toEqual(['node'])

+ 4 - 3
packages/sdk/helper/src/features/builtin/app.ts

@@ -4,6 +4,7 @@
  * @module @deepseek-ai/dsh-helper/features/builtin/app
  */
 
+import { JsExpression } from '../../documents/cordis-yaml-file.ts'
 import { featureId } from '../../ids.ts'
 import type { ProjectProfile } from '../../project/types.ts'
 import {
@@ -94,11 +95,11 @@ class AppOption extends FeatureOption {
             name: '@deepseek-ai/dsh-stdio',
             config: {
               welcome: 'agent REPL ready. Give it a coding task.',
-              agent: 'main',
+              sessionId: new JsExpression('process.env.DSH_SDK_SESSION_ID'),
             },
-          }, ['welcome', 'agent'], config => [
+          }, ['welcome', 'sessionId'], config => [
             ...optionalString(config, 'welcome'),
-            ...requiredString(config, 'agent'),
+            ...config.sessionId instanceof JsExpression ? [] : requiredString(config, 'sessionId'),
           ]),
         ])
       case 'embed':

+ 7 - 7
packages/sdk/helper/src/templates/assets/index.ts.tpl

@@ -2,14 +2,12 @@
 import { startSDK, type SdkBootContext } from '@deepseek-ai/dsh-scripts'
 {{else}}
 import { randomUUID } from 'node:crypto'
-import { AgentId } from '@deepseek-ai/dsh-agent'
 import { SessionId } from '@deepseek-ai/dsh-session'
 import { startSDK, type SdkBootContext } from '@deepseek-ai/dsh-scripts'
 {{/if}}
 
 /** Boot this project's cordis.yml when invoked by dsh-scripts. */
 export async function main(boot: SdkBootContext) {
-  const ctx = await startSDK(new URL('./cordis.yml', import.meta.url))
 {{#if isStdio}}
   const model = boot.args.model
   if (typeof model !== 'string' || model.length === 0) throw new Error('stdio startup requires --model=<name>')
@@ -17,24 +15,26 @@ export async function main(boot: SdkBootContext) {
   if (resume !== undefined && (typeof resume !== 'string' || resume.length === 0)) {
     throw new Error('stdio startup requires --resume=<session-id>')
   }
+  const sessionId = SessionId(resume ?? `main-session-${randomUUID()}`)
+  process.env.DSH_SDK_SESSION_ID = sessionId
+{{/if}}
+  const ctx = await startSDK(new URL('./cordis.yml', import.meta.url))
+{{#if isStdio}}
   if (resume === undefined) {
     await ctx.agents.create({
-      agentId: AgentId('main'),
-      sessionId: SessionId(`main-session-${randomUUID()}`),
+      sessionId,
       meta: { cwd: boot.cwd },
       agentOptions: { model },
     })
   } else {
     await ctx.agents.resume({
-      agentId: AgentId('main'),
-      resumeSessionId: SessionId(resume),
+      resumeSessionId: sessionId,
       agentOptions: { model },
     })
   }
 {{else}}
 {{#if isEmbed}}
   await ctx.agents.create({
-    agentId: AgentId('main'),
     sessionId: SessionId(`main-session-${randomUUID()}`),
     meta: { cwd: boot.cwd },
     agentOptions: { model: {{modelLiteral}} },

+ 13 - 2
packages/sdk/helper/tests/project.spec.ts

@@ -167,6 +167,10 @@ describe('SdkProject and ProjectEditSession', () => {
     expect(index).toContain('SdkBootContext')
     expect(index).toContain('agents.create')
     expect(index).toContain('boot.args.resume')
+    expect(index).not.toContain('AgentId')
+    expect(index).toContain('const sessionId = SessionId(resume ?? `main-session-${randomUUID()}`)')
+    expect(index).toContain('process.env.DSH_SDK_SESSION_ID = sessionId')
+    expect(index).toContain('resumeSessionId: sessionId')
     expect(project.packageManifest().scripts).toEqual({
       dev: 'dsh-sdk dev index.ts -- --model="deepseek-v4-flash"',
       build: 'dsh-sdk build',
@@ -175,7 +179,11 @@ describe('SdkProject and ProjectEditSession', () => {
       config: 'dsh-sdk config',
     })
     expect(await readFile(join(project.root, '.env.example'), 'utf8')).toContain('EXA_API_KEY=')
-    expect(project.cordis.entry('stdio')?.config).toMatchObject({ agent: 'main' })
+    expect(project.cordis.entry('stdio')?.config?.sessionId).toMatchObject({
+      source: 'process.env.DSH_SDK_SESSION_ID',
+    })
+    expect(await readFile(join(project.root, 'cordis.yml'), 'utf8'))
+      .toContain('sessionId: !!js process.env.DSH_SDK_SESSION_ID')
     expect(project.cordis.entry('stdio')?.config).not.toHaveProperty('model')
     expect(project.cordis.entry('agent-loop')?.config).toEqual({ agents: [] })
     expect(project.cordis.entry('system-prompt')?.config?.persona).toContain('{{cwd}}')
@@ -286,7 +294,10 @@ describe('SdkProject and ProjectEditSession', () => {
     const embed = (await embedEdit.commit()).project
     expect(embed.profile.runInterface).toBe('embed')
     expect(await readFile(join(embed.root, 'README.md'), 'utf8')).toContain('Embed the harness')
-    expect(await readFile(join(embed.root, 'index.ts'), 'utf8')).toContain('agents.create')
+    const embedIndex = await readFile(join(embed.root, 'index.ts'), 'utf8')
+    expect(embedIndex).toContain('agents.create')
+    expect(embedIndex).toContain("import { SessionId } from '@deepseek-ai/dsh-session'")
+    expect(embedIndex).not.toContain('AgentId')
 
     await writeFile(join(embed.root, 'README.md'), '# Custom README\n')
     const modified = await SdkProject.open(embed.root)

+ 2 - 2
packages/ui/acp/README.md

@@ -8,7 +8,7 @@ It is a **client-driver / UI plugin**, the structured analogue of the readline `
 
 `apply(ctx, config)` — wires an `AgentSideConnection` (from `@agentclientprotocol/sdk`) to `process.stdin`/`process.stdout` and implements the ACP `Agent` method surface.
 
-The plugin injects `agents`, `sessions`, `sessionPersistence`, `tools`, and `userInteraction`, never the concrete loop. Persistence backs `session/load`; tool definitions own presentation; user interaction maps agent questions to ACP forms.
+The plugin injects `agents`, `sessionPersistence`, `tools`, and `userInteraction`, never the concrete loop. Persistence backs `session/load`; tool definitions own presentation; user interaction maps agent questions to ACP forms.
 
 ### Config
 
@@ -36,7 +36,7 @@ The `initialize` handshake reports a fixed server identity (`agentInfo: { name:
 
 ## Multi-session
 
-Forward and reverse indexes route every event, prompt, cancel, and approval to one session. Each session permits one in-flight prompt; teardown drains all sessions in parallel. See the [multi-session RFC](../../../docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md).
+One id-keyed record map plus exact agent-object checks route every event, prompt, cancel, and approval to one session. Each session permits one in-flight prompt; teardown drains all sessions in parallel. See the [multi-session RFC](../../../docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md).
 
 ## Session config options