Merge updated feedback base into telemetry stack
# Conflicts: # .agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.i18n.yaml # .agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.zh.md # .agents/notes/implemented/feature/2026-07-28-feedback-command.i18n.yaml # docs/config-catalog.md # docs/event-producer-consumer.md # docs/module-graph.md # examples/package.json # packages/feedback/command-feedback/README.i18n.yaml # packages/telemetry/README.i18n.yaml # packages/telemetry/README.md # packages/telemetry/README.zh.md # packages/telemetry/session-telemetry-otel/README.i18n.yaml # packages/telemetry/session-telemetry-otel/README.md # packages/telemetry/session-telemetry-otel/README.zh.md # packages/telemetry/session-telemetry-otel/package.json # packages/telemetry/session-telemetry-otel/src/index.ts # packages/telemetry/session-telemetry-otel/tests/otel.spec.ts # packages/telemetry/session-telemetry/README.i18n.yaml # packages/telemetry/session-telemetry/README.zh.md # pnpm-lock.yaml
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/feedback/command-feedback/README.md
|
||||
README.md: e3b0e58f1746c7bcd1c74ac0990a872a1f24d7d7
|
||||
README.zh.md: 40ec871caff6f90b0b1c685e833c874e32a48d16
|
||||
README.md: 1923267eb3a25a4be564fa4f4535f7a3459ca481
|
||||
README.zh.md: 674665167030aa6214e9acaa7e6f5314a78c5b14
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
Trigger-independent session feedback plus human-facing `/feedback` capture. The package exports `recordFeedback(session, text)`, which appends one log-only `feedback/record` event. Its plugin registers one global command through [`ctx.commands`](../../ui/commands/README.md), so every composed command adapter discovers it; the shipped TUI executes it without a model turn.
|
||||
Trigger-independent session feedback plus human-facing `/feedback` capture. The package exports `recordFeedback(session, text)`, which appends one log-only `feedback/record` event. Its plugin registers one global command through [`ctx.commands`](../../ui/commands/README.md), so every composed command adapter discovers it; the shipped Web client executes it without a model turn.
|
||||
|
||||
## Command contract
|
||||
|
||||
@@ -32,7 +32,7 @@ The producer injects only `commands`. A custom app mounts the registry plus this
|
||||
name: '@deepseek-ai/dsh-command-feedback'
|
||||
```
|
||||
|
||||
The TUI app mounts this command unconditionally; it has no configuration and no dependency on the persisted-goal stack. The headless CLI, ACP automation, and JSON-RPC adapters do not consume `ctx.commands`, so they do not expose it.
|
||||
The shipped `dsh` base mounts this command unconditionally; it has no configuration and no dependency on the persisted-goal stack. The Web client exposes it through the command adapter. Headless mode, ACP automation, and JSON-RPC do not provide a command adapter, so they do not expose it.
|
||||
|
||||
## Model Experience
|
||||
|
||||
@@ -56,4 +56,4 @@ Independent of the model request path. Recording appends to the session log only
|
||||
- **No structured fields** — an entry is one free-text string with no category, severity, or referenced-event link, so feedback cannot be filtered by subject without re-reading its text.
|
||||
- **No amend or withdraw** — the session log is append-only and this package adds no tombstone, so a mistaken entry stays recorded and can only be superseded by a later one.
|
||||
- **No explicit durability barrier** — the acknowledgement follows the append, not a flush, so an entry recorded immediately before a crash can be lost with any other unflushed tail. Feedback is not worth forcing a synchronous disk write for; a consumer that needs one awaits `ctx.sessions.flush(session)`.
|
||||
- **TUI only in the shipped apps** — the headless CLI, ACP automation, and JSON-RPC adapters do not mount `ctx.commands`, so `/feedback` is unavailable there.
|
||||
- **Web only in the shipped front doors** — headless mode, ACP automation, and JSON-RPC do not provide a command adapter, so `/feedback` is unavailable there.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
与触发方式无关的会话反馈,以及面向用户的 `/feedback` 采集。本包(package)导出 `recordFeedback(session, text)`,后者追加一个仅写入日志的 `feedback/record` 事件。该插件通过 [`ctx.commands`](../../ui/commands/README.md) 注册一个全局命令,因此每个已组合的命令适配器都能发现它;随附 TUI 无需模型轮次即可执行。
|
||||
与触发方式无关的会话反馈,以及面向用户的 `/feedback` 采集。本包导出 `recordFeedback(session, text)`,后者追加一个仅写入日志的 `feedback/record` 事件。该插件通过 [`ctx.commands`](../../ui/commands/README.md) 注册一个全局命令,因此每个已组合的命令适配器都能发现它;随附的 Web 客户端无需模型轮次即可执行。
|
||||
|
||||
## 命令契约
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
name: '@deepseek-ai/dsh-command-feedback'
|
||||
```
|
||||
|
||||
TUI 应用无条件挂载此命令;它没有配置,也不依赖持久 goal 栈。无头 CLI、ACP 自动化和 JSON-RPC 适配器不消费 `ctx.commands`,因此不会暴露它。
|
||||
随附的 `dsh` 基础组合无条件挂载此命令;它没有配置,也不依赖持久 goal 栈。Web 客户端通过命令适配器暴露该命令。无头模式、ACP 自动化和 JSON-RPC 不提供命令适配器,因此不会暴露它。
|
||||
|
||||
## 模型体验
|
||||
|
||||
@@ -56,4 +56,4 @@ TUI 应用无条件挂载此命令;它没有配置,也不依赖持久 goal
|
||||
- **没有结构化字段**:一条条目就是一个自由文本字符串,没有类别、严重程度或关联事件链接,因此无法在不重读文本的情况下按主题过滤反馈。
|
||||
- **不支持修改或撤回**:会话日志是仅追加的,本包也不新增 tombstone,因此错误的条目会一直保留在记录中,只能由后续条目取代。
|
||||
- **没有显式持久化屏障**:确认文本紧随追加而非 flush,因此紧临崩溃前记录的条目可能与其他未 flush 的尾部一同丢失。为反馈强制同步写盘并不值得;需要该保证的消费方可自行等待 `ctx.sessions.flush(session)`。
|
||||
- **随附应用中只有 TUI 使用此命令**:无头 CLI、ACP 自动化和 JSON-RPC 适配器不挂载 `ctx.commands`,因此 `/feedback` 在那里不可用。
|
||||
- **随附的产品入口中只有 Web 使用此命令**:无头模式、ACP 自动化和 JSON-RPC 不提供命令适配器,因此 `/feedback` 在那里不可用。
|
||||
@@ -21,9 +21,7 @@
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/types/**/*.d.ts",
|
||||
"lib/types/**/*.d.ts.map",
|
||||
"src"
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import Loader from '@cordisjs/plugin-loader'
|
||||
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
||||
import AgentRegistry, { Inbox } from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent, AgentStatus } from '@deepseek-ai/dsh-agent'
|
||||
import CommandService from '@deepseek-ai/dsh-commands'
|
||||
import SessionStore, { foldSurface, Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
@@ -17,19 +17,21 @@ interface Harness {
|
||||
/** Build a live idle agent over a store-owned session, as an app's spine does. */
|
||||
function stubAgent(ctx: Context, id: string): { agent: Agent; session: Session } {
|
||||
const session = ctx.sessions.create(SessionId(id))
|
||||
const inbox = new Inbox(session, { inserted: () => {}, discarded: () => {}, claimed: () => {} })
|
||||
let status: AgentStatus = 'idle'
|
||||
const agent: Agent = {
|
||||
id: session.id,
|
||||
options: {},
|
||||
session,
|
||||
inbox,
|
||||
ctx: new Context(),
|
||||
get status() { return status },
|
||||
get acceptsNextStep() { return status === 'running' },
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
cancel() { status = 'idle' },
|
||||
runMaintenance: task => task(new AbortController().signal),
|
||||
whenIdle() { return Promise.resolve() },
|
||||
}
|
||||
return { agent, session }
|
||||
@@ -133,7 +135,7 @@ describe('/feedback human command', () => {
|
||||
it('records concurrent submissions in dispatch order', async () => {
|
||||
const test = await harness()
|
||||
const signal = new AbortController().signal
|
||||
// The shipped TUI dispatches commands fire-and-forget.
|
||||
// Command adapters may dispatch concurrent requests without awaiting one another.
|
||||
const settled = await Promise.all([
|
||||
test.ctx.commands.execute(test.agent, '/feedback first', signal),
|
||||
test.ctx.commands.execute(test.agent, '/feedback second', signal),
|
||||
|
||||
@@ -6,7 +6,7 @@ import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import Loader from '@cordisjs/plugin-loader'
|
||||
import Include from '@cordisjs/plugin-include'
|
||||
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
||||
import AgentRegistry, { Inbox } from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent, AgentStatus } from '@deepseek-ai/dsh-agent'
|
||||
import CommandService from '@deepseek-ai/dsh-commands'
|
||||
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
|
||||
@@ -27,19 +27,21 @@ function agent(ctx: Context): Agent {
|
||||
const scope = ctx.plugin(() => {})
|
||||
const id = SessionId('feedback-loader-agent')
|
||||
const session = ctx.sessions.create(id)
|
||||
const inbox = new Inbox(session, { inserted: () => {}, discarded: () => {}, claimed: () => {} })
|
||||
let status: AgentStatus = 'idle'
|
||||
const value: Agent = {
|
||||
id,
|
||||
options: {},
|
||||
session,
|
||||
inbox,
|
||||
ctx: scope.ctx,
|
||||
get status() { return status },
|
||||
get acceptsNextStep() { return status === 'running' },
|
||||
send: () => {},
|
||||
followup: () => {},
|
||||
steer: () => {},
|
||||
inject: () => {},
|
||||
cancel() { status = 'idle' },
|
||||
runMaintenance: task => task(new AbortController().signal),
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
ctx.agents.register(value)
|
||||
|
||||
Reference in New Issue
Block a user