Skip to content

feat(chat): support --at-users on chat message reply - #794

Open
mvanhorn wants to merge 4 commits into
DingTalk-Real-AI:mainfrom
mvanhorn:fix/359-reply-at-users
Open

feat(chat): support --at-users on chat message reply#794
mvanhorn wants to merge 4 commits into
DingTalk-Real-AI:mainfrom
mvanhorn:fix/359-reply-at-users

Conversation

@mvanhorn

Copy link
Copy Markdown

Closes #359. Supersedes #451.

@PeterGuy326 关闭 #451 时说明:需求本身仍有效,但那份实现基于 #565 之前的
executor/helper command 架构,而 reply 现已改为静态 handler,文件与主干大幅漂移,
且未覆盖当前 Schema contract,并欢迎基于最新 main 提交新的聚焦 PR。这就是那份新 PR。

改动

dws chat message reply 新增 --at-users,接受逗号分隔的 userId 或
openDingTalkId:

  • userId 通过既有的 resolveOpenDingTalkIDs 解析为 openDingTalkId;已是
    openDingTalkId 的值原样保留。
  • 回复正文中对应的 @ 标识由 normalizeAtPlaceholders(wrapAngle=true) 统一为
    <@openDingTalkId>,与 message send 处理用户身份消息的方式一致。
  • 解析结果以 atOpenDingTalkIds 随工具参数下发。

未引入新的辅助函数,全部复用 message send 已有的 at-mention 路径。

Schema contract

这是 #451 缺失的部分,本 PR 一并更新:

  • internal/cli/schema_catalog.json
  • internal/cli/schema_parameter_bindings.json
  • internal/cli/schema_agent_metadata/chat.jsonindex.json
  • internal/cli/schema_agent_metadata_audit.json
  • internal/cli/schema_hints/selection/chat.json

文档与测试

  • skills/mono/references/products/chat.md
    skills/multi/dingtalk-chat/references/chat.md 同步说明与示例。
  • CHANGELOG 条目。
  • 新增 internal/helpers/chat_message_reply_at_users_test.go

验证

go build ./...go vet ./... 通过;internal/helpersinternal/app
internal/cli 全部通过。

@github-actions
github-actions Bot requested a review from audanye-sudo July 25, 2026 23:22
@github-actions
github-actions Bot enabled auto-merge July 25, 2026 23:22
mvanhorn added 2 commits July 27, 2026 06:50
Closes DingTalk-Real-AI#359. Rebuilt on current main per @PeterGuy326's review of DingTalk-Real-AI#451, which
was written against the pre-DingTalk-Real-AI#565 executor/helper architecture and did not cover
the current Schema contract.

reply now accepts a comma-separated --at-users list of userIds or
openDingTalkIds. userIds resolve to openDingTalkIds via the existing
resolveOpenDingTalkIDs helper, and the matching @ markers in the reply body are
normalized to <@openDingTalkId> with normalizeAtPlaceholders(wrapAngle=true) --
the same shape message send uses for user-identity messages. Resolved ids are
forwarded as atOpenDingTalkIds.

Schema catalog, parameter bindings, agent metadata and selection hints are
updated alongside, plus both chat reference docs and a test.

Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
The generated artifacts conflicted on their source_hash fields against 31
commits of main. Regenerated with make generate-schema-agent-metadata and
make generate-schema-catalog rather than hand-merging the hashes.
auto-merge was automatically disabled July 27, 2026 13:57

Head branch was pushed to by a user without write access

@mvanhorn
mvanhorn force-pushed the fix/359-reply-at-users branch from e7674ce to a1f7dfa Compare July 27, 2026 13:57
@github-actions
github-actions Bot enabled auto-merge July 27, 2026 13:57
The coverage gate wants 100% on changed code and was at 97.4359% (38 of 39
statements). The gap was the error branch that reports an unresolvable
--at-users value. Added a case where the directory lookup returns no mapping,
asserting the command errors and does not send the reply with an unresolved @.
auto-merge was automatically disabled July 27, 2026 14:18

Head branch was pushed to by a user without write access

@github-actions
github-actions Bot enabled auto-merge July 27, 2026 14:18
@mvanhorn

Copy link
Copy Markdown
Author

Rebased onto main and got CI green -- a1f7dfa + fda8cf2.

The branch was 31 commits behind, which is what all four red checks came down to. Test (workflow and release contracts) was failing on TestReleaseWorkflowWaitsForNPMDistTagPropagation/stale_beta_never_converges, in test/scripts/package_script_test.go -- a file this PR doesn't touch. That test passes on main, and it passes here after the rebase; Coverage, Policy and Test were all reporting the same underlying failure.

The rebase conflicted only on generated artifacts (schema_catalog.json, schema_agent_metadata/index.json, schema_agent_metadata_audit.json), all on source_hash fields. Rather than hand-merge hashes I took main's copies and re-ran make generate-schema-agent-metadata + make generate-schema-catalog.

That left the coverage gate at 97.4359% on changed code against a 100% target -- 38 of 39 statements. The one gap was the branch that reports an unresolvable --at-users value. fda8cf2 adds a case where the directory lookup returns no mapping, asserting the command errors and doesn't send a reply containing an unresolved @. chat.go now has no uncovered blocks.

Everything is green.

auto-merge was automatically disabled August 1, 2026 05:14

Head branch was pushed to by a user without write access

@github-actions
github-actions Bot enabled auto-merge August 1, 2026 05:14
@mvanhorn

mvanhorn commented Aug 1, 2026

Copy link
Copy Markdown
Author

Merged main. The branch is mergeable again and the only red check is a macOS timeout that also happens on main.

What the merge needed, since main moved a fair way:

  • The generated schema artifacts were not merged textually. I took main's copies and reran make generate-schema, so schema_agent_metadata, the audit file, the catalog and param_aliases_generated.go are all generator output rather than hand-resolved JSON.
  • schema_catalog.json was deleted upstream. I accepted the deletion; the same target regenerates it.
  • schema_parameter_bindings.json keeps the reply at-users -> atOpenDingTalkIds mapping, and the reviewed baseline hash is updated to the resulting manifest. That mapping is what TestChatSchemaSeparatesSendAndReply asserts, so it fails loudly if the binding is ever dropped again.
  • The chat docs were restructured on main from one file into a routing layer with details under references/chat/. The --at-users documentation went into references/chat/chat-message.md rather than into the old monolith.

On the failing check. Test (macOS auth/keychain) runs

go test -v -race -count=1 -timeout=10m ./internal/keychain ./internal/auth ./internal/app

and internal/app hit panic: test timed out after 10m0s. It is not an assertion failure and I do not think it is this PR. Measured on the same machine, same command:

this branch   internal/app -race   470.9s
main alone    internal/app -race   552.4s

So main is already at roughly 92 percent of the 10 minute budget by itself, and this branch is not slower than main. A GitHub macOS runner is slower than my laptop, which is enough to push it over.

Locally the full job command passes: go test -race -count=1 ./internal/keychain ./internal/auth ./internal/app is 6349 tests green. Policy, Lint, CLI Smoke, Edition, Mock MCP, Windows, cross-platform compile and the race shards are all green in CI.

If you want, the cheap fix is raising -timeout on that one job, or splitting internal/app out of the macOS shard. Happy to do either here or leave it for a separate PR since it affects main too.

@mvanhorn

mvanhorn commented Aug 2, 2026

Copy link
Copy Markdown
Author

The two red Test jobs look like a suite-duration problem rather than a failure in this change.

internal/app is hitting Go's default 10-minute limit: the run ends with panic: test timed out after 10m0s and FAIL github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/app 600.144s. The test named as running at that moment had only been going 6s, so it isn't a hang in one test — the package as a whole is just at the edge of the budget. #830 fails the same way.

This PR adds 7 lines to internal/app/schema_contract_test.go, which is presumably enough to tip it over on a slower runner.

A re-run would probably be enough to tell whether it's marginal or consistently over, but gh run rerun needs admin on the repo so I can't trigger one. If it is consistently over, raising -timeout for that package or splitting it would be the durable fix — happy to send that separately if you'd like it.

Main moved on, so the generated artifacts were taken from main and regenerated
rather than merged textually:

- schema_agent_metadata, the audit file and param_aliases_generated.go come from
  `make generate-schema` on top of main, not from resolving the JSON by hand.
- schema_catalog.json was deleted upstream, so that deletion is accepted and the
  catalog is regenerated by the same target.
- schema_parameter_bindings.json keeps the chat reply at-users -> atOpenDingTalkIds
  mapping, with the reviewed baseline hash updated to the resulting manifest.

The chat docs were restructured on main from one file into a routing layer with
details under references/chat/, so the --at-users documentation was ported into
references/chat/chat-message.md instead of merged into the old monolith.

go build ./... is clean, and internal/helpers, internal/app and internal/cli all
pass. make lint reports pre-existing findings in nine files that are byte
identical to main and untouched here.
auto-merge was automatically disabled August 2, 2026 20:30

Head branch was pushed to by a user without write access

@mvanhorn
mvanhorn force-pushed the fix/359-reply-at-users branch from 650e1c9 to d364744 Compare August 2, 2026 20:30
@github-actions
github-actions Bot enabled auto-merge August 2, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 期望 dws chat message reply 支持 --at-users

1 participant