Skip to content

Merge dev into feature/memory-embeddings - #1601

Merged
Aaronontheweb merged 9 commits into
netclaw-dev:feature/memory-embeddingsfrom
Aaronontheweb:sync/dev-into-memory-embeddings
Jul 8, 2026
Merged

Merge dev into feature/memory-embeddings#1601
Aaronontheweb merged 9 commits into
netclaw-dev:feature/memory-embeddingsfrom
Aaronontheweb:sync/dev-into-memory-embeddings

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Summary

Test plan

  • dotnet build Netclaw.slnx -c Debug succeeds with 0 warnings/errors after the merge
  • CI (pr_validation, smoke) passes on this PR

Aaronontheweb and others added 8 commits July 5, 2026 21:17
…tclaw-dev#1583)

* test: add failing tests for BOM frontmatter parsing and missing SkillName in issues

* fix: handle UTF-8 BOM in ExtractFrontmatter and populate SkillName on all issues

- Strip UTF-8 BOM (\uFEFF) before checking for YAML frontmatter delimiter
- Populate SkillName on all SkillScanIssue records created in SkillScanner
- Fix BOM check in ParseSkillFile and ParseFlatSkillFile for issue kind determination

Fixes netclaw-dev#1582

* fix(skills): prevent scan-aborting crash on degenerate frontmatter; normalize issue SkillNames

Review follow-ups on the BOM/SkillName change:

- ExtractFrontmatter threw ArgumentOutOfRangeException on a degenerate
  "---\n---" block (empty YAML body): the opening line's newline is also
  the closing delimiter, so the slice computed a negative-length range.
  Because Scan's parse calls are unguarded, this propagated out and aborted
  the entire skill-discovery pass (no skills loaded at all). Since
  File.ReadAllText strips the BOM, a plain "---\n---" SKILL.md on disk hit
  this too. Now guarded to return null (reported as invalid frontmatter).

- ResourceEnumerationFailed derived SkillName from the parent directory
  (Path.GetDirectoryName(skillDirectory)), yielding the container name
  ("files") instead of the skill name. Fixed to use the leaf directory.

- Normalized all error-path SkillName derivations via NormalizeSkillName so
  errored rows render the canonical lowercased name, consistent with
  accepted skills.

- Removed dead caller-side content.TrimStart('') no-ops: content comes
  from File.ReadAllText which already strips the BOM, so BOM tolerance lives
  solely in ExtractFrontmatter.

Adds regression tests: degenerate-block returns null (does not throw), Scan
survives a degenerate SKILL.md and keeps discovering healthy siblings, and
issue SkillNames are normalized from mixed-case directories.
* chore: bump SkillServer to 0.4.0-beta.3 and adapt to API changes

* fix: update test mocks to use v1 API paths

* test: align sidecar mock with v1 API
---
updated-dependencies:
- dependency-name: Grpc.Tools
  dependency-version: 2.82.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ev#1596)

---
updated-dependencies:
- dependency-name: Netclaw.SkillClient
  dependency-version: 0.4.0-beta.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…law-dev#1597) (netclaw-dev#1600)

Sub-agent LLM calls never recorded token usage, so every sub-agent's
input/output tokens were invisible to `netclaw stats`. This was a
pre-existing gap, not a regression: SubAgentActor never had an
ISessionMetrics dependency and discarded the ChatResponse.Usage it already
receives from StreamingResponseReader. The recent observability PRs
(netclaw-dev#1428, netclaw-dev#1468, netclaw-dev#1472/netclaw-dev#1499) only added logs and pruned dead OTel Activities;
none ever touched token tracking.

Fix records at the source, mirroring the main session:
- Inject ISessionMetrics into SubAgentActor (via SubAgentSpawner/CreateProps).
  DI already registers it as a process-wide singleton, so no Program.cs change.
- Record response.Usage on every LlmResponseReceived (one per LLM turn:
  tool-call turns, retries, the forced-no-tools final turn, repair turns).
- Add cumulative input/output token totals to the completion summary log.

Recorded in the child, not propagated to the parent: ISessionMetrics is the
SAME process-wide singleton both share, so re-recording in the parent would
double-count, and folding sub-agent tokens into the parent's UsageOutput
would corrupt its context-window percentage (the sub-agent has its own
context window).

Regression coverage (all four fail if the recording is removed):
- SubAgentActor bills usage per LLM call and sums across the turn loop.
- Completion summary log carries token totals.
- Full spawner->CreateProps->actor wiring bills tokens to the spawner's metrics.

Adds a UsageOverride hook to the sub-agent test FakeChatClient and extracts a
shared RecordingSessionMetrics test helper.
@Aaronontheweb
Aaronontheweb merged commit 4d6f365 into netclaw-dev:feature/memory-embeddings Jul 8, 2026
15 checks passed
@Aaronontheweb
Aaronontheweb deleted the sync/dev-into-memory-embeddings branch July 8, 2026 18:31
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.

1 participant