Skip to content

feat(sec-core): cosh hook for security observability#528

Open
RemindD wants to merge 1 commit into
alibaba:mainfrom
RemindD:feature/sec-core/coshob
Open

feat(sec-core): cosh hook for security observability#528
RemindD wants to merge 1 commit into
alibaba:mainfrom
RemindD:feature/sec-core/coshob

Conversation

@RemindD
Copy link
Copy Markdown
Collaborator

@RemindD RemindD commented May 14, 2026

Description

Register a cosh extension hook that records prompt, model, tool, and stop events through agent-sec-cli observability record. The hook maps available hook payload fields into observability metrics, fills stable metadata with synthetic IDs when needed, and always emits an empty hook output so it does not affect run decisions.

Add unit coverage for event mapping, payload sizing, synthetic metadata, invalid input handling, no-op output, and best-effort CLI invocation.

Related Issue

closes #

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional change)
  • Performance improvement
  • CI/CD or build changes

Scope

  • cosh (copilot-shell)
  • sec-core (agent-sec-core)
  • skill (os-skills)
  • sight (agentsight)
  • tokenless (tokenless)
  • Multiple / Project-wide

Checklist

  • I have read the Contributing Guide
  • My code follows the project's code style
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the documentation accordingly
  • For cosh: Lint passes, type check passes, and tests pass
  • For sec-core (Rust): cargo clippy -- -D warnings and cargo fmt --check pass
  • For sec-core (Python): Ruff format and pytest pass
  • For skill: Skill directory structure is valid and shell scripts pass syntax check
  • For sight: cargo clippy -- -D warnings and cargo fmt --check pass
  • For tokenless: cargo clippy -- -D warnings and cargo fmt --check pass
  • Lock files are up to date (package-lock.json / Cargo.lock)

Testing

Additional Notes

@github-actions github-actions Bot added the component:sec-core src/agent-sec-core/ label May 14, 2026
@RemindD RemindD force-pushed the feature/sec-core/coshob branch from c88c3e6 to 7fb8ead Compare May 14, 2026 08:47


def _record_observability(record: dict[str, Any]) -> None:
subprocess.run(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] 在 BeforeModel / AfterModel / PreToolUse / PostToolUse / PostToolUseFailure / Stop / UserPromptSubmit 七个事件都会同步 fork 一个 python3 → agent-sec-cli observability record 子进程(CLI 是 Python 入口)会有性能问题,后续需要考虑优化

metadata = {
"sessionId": _string_or_empty(input_data.get("session_id")),
"runId": _string_or_empty(input_data.get("run_id"))
or _synthetic_id("run", input_data),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runID 来自 sha256(_json_dumps(input_data))[:16],再被 _metadata 用作 runId 的 fallback,同一 run 的 UserPromptSubmit、BeforeModel、PreToolUse、Stop payload 内容各不相同,因此每个事件会得到一个不同的 synthetic-run-XXX,这样能够满足 session 关联的要求吗?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cosh 的runId是通过prompt id 继承的,格式为{sessionId}##..##{turnid}, e.g. b56f109e-c704-49be-bdce-d7e003d34445########0. 在每一次prompt 对话中都是保持一致的。唯一的例外的UserPromptSubmit的runId,因为hook 运行时runid未赋值,会找到legacy的值。在issue #531 中追踪。

if not isinstance(llm_response, dict):
llm_response = {}

metrics: dict[str, Any] = {"outcome": "success"}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

硬编码成 "success"?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前cosh 侧只有在LLM call 成功时才会进AfterModel hook。如果LLM call 失败了,会被cosh core catch,失败的原因并没有暴露给任何cosh hook

LLM call 失败后的主路径是:

用户消息
-> BeforeModel hook
-> 调 LLM / 读 stream
-> 失败抛错
-> turn.ts catch
-> yield GeminiEventType.Error
-> client.ts 收到 Error 后 return

结果是:

  • 不会走 AfterModel
  • 不会自动进入 tool call 阶段
  • 不会有正常 assistant reply
  • 不会触发 Stop hook
  • 用户可以之后再发新消息,但这是下一轮,不是当前失败 LLM call 的后续



def _build_post_tool_use(input_data: dict[str, Any]) -> dict[str, Any] | None:
metrics: dict[str, Any] = {"status": "success"}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

硬编码?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after tool call hook 分为post_tool_use和post_tool_use_failure,所以post_tool_use的hook 中的status 硬编码成了success。对于post_tool_use_failure,会区分是interrupted 还是error

def _build_post_tool_use_failure(input_data: dict[str, Any]) -> dict[str, Any] | None:
metrics: dict[str, Any] = {
"status": "interrupted" if input_data.get("is_interrupt") is True else "error"
}

Comment thread src/agent-sec-core/cosh-extension/hooks/observability_hook.py
@RemindD RemindD force-pushed the feature/sec-core/coshob branch from 7fb8ead to af76bf4 Compare May 15, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:sec-core src/agent-sec-core/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants