Skip to content

Refactor/project namespace#1

Merged
eanzhao merged 4 commits into
masterfrom
refactor/project-namespace
Feb 16, 2026
Merged

Refactor/project namespace#1
eanzhao merged 4 commits into
masterfrom
refactor/project-namespace

Conversation

@loning
Copy link
Copy Markdown
Contributor

@loning loning commented Feb 14, 2026

No description provided.

…ions and Aevatar.AI.Core. Update project references and namespaces across demos and samples. Remove obsolete ai_messages.proto file and implement new LLM provider interfaces and agent configurations. Enhance chat runtime and history management for improved AI agent functionality.
…ences and implement connector registration. Refactor MakerRunRecorder and ChatRunRecorder to improve payload handling. Introduce IAevatarSecretsStore for enhanced secrets management.
…ntation. Update IStream interface to remove unnecessary constraints and improve type handling in InMemoryStream. Enhance CORS policy in API to default to deny all origins in production unless explicitly configured. Refactor ChatEndpoints to streamline event processing logic.
@eanzhao eanzhao merged commit 0557050 into master Feb 16, 2026
2 checks passed
eanzhao added a commit that referenced this pull request Apr 27, 2026
…ServiceId; share contract math

Addresses PR #457 review.

## Functional fix (the inline review): InvokePath / invoke handler mismatch

The contract returned by the new `GET /members/.../endpoints/.../contract`
was telling the frontend to call `/members/{memberId}/invoke/...`, but the
existing platform handler for that path resolves the member through
`IMemberPublishedServiceResolver` which today returns
`publishedServiceId == memberId`. Studio's bind path persists
`publishedServiceId == "member-{memberId}"`. So the contract was built for
`member-{memberId}` while invoke would target `{memberId}` → 404.

Fix: register `StudioAwareMemberPublishedServiceResolver` from Studio's
DI. It first asks `IStudioMemberQueryPort` for the member's stored
`publishedServiceId`; if no Studio member exists, falls back to the
legacy deterministic mapping (`memberId == publishedServiceId`) so
direct platform binds keep working unchanged. Now contract / activate /
retire / invoke / runs all resolve to the same identity.

## Refactors per the PR review

- **#1 Duplicated contract-building logic**: extracted the pure
  helpers (`ResolveCurrentContractRevision`,
  `EnumeratePreferredContractRevisionIds`, `RevisionContainsEndpoint`,
  `IsChatEndpoint`, `ResolveStreamFrameFormat`,
  `BuildBase64PayloadPlaceholder`, `BuildTypedInvokeRequestExampleBody`)
  into `Aevatar.GAgentService.Abstractions.Services.ServiceEndpointContractMath`.
  Both `ScopeServiceEndpoints.cs` (legacy) and `StudioMemberService.cs`
  (member-first) funnel through it. A bug fix in one helper now
  propagates to both paths automatically.

- **#3 / #4 Repeated resolve+verify pattern**: introduced
  `ResolveBoundServiceContextAsync` returning
  `(ScopeId, MemberId, PublishedServiceId, Identity, Service, Revisions)`.
  The three new methods now all share one query path; activate /
  retire dropped from 4 platform queries to 2.

- **#2 Non-atomic activate**: documented with a `NOTE:` comment that
  `SetDefaultServingRevision` then `ActivateServiceRevision` is
  intentionally non-transactional, mirroring the legacy scope-default
  behavior, and that both commands are platform-side idempotent.

- **#7 Hardcoded "retired" string**: introduced
  `MemberRevisionLifecycleStatusNames.Retired` next to the existing
  `MemberLifecycleStageNames` so future lifecycle verbs declare
  themselves alongside it instead of as scattered magic strings.

- **#6 / #8 Input trimming**: collapsed the four ad-hoc trimming sites
  into a single `NormalizeRequired(value, fieldName)` helper applied at
  the service entry of every public method. Trimming now happens at
  exactly one boundary per call.

## Tests

- 13 new tests pin the resolver's contract (Studio member → stored
  publishedServiceId; non-Studio member → legacy fallback; trim;
  reject malformed input; empty publishedServiceId degrades safely).
- Existing tests unchanged: 327 Studio + 281 platform integration
  passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eanzhao added a commit that referenced this pull request Apr 27, 2026
P1 — workflow termination on publish failure (reviewer's critical):
`PublishFailureAsync` emits `StepCompletedEvent { Success = false }`,
which the kernel routes through `TryRetryAsync` → `TryOnErrorAsync` →
fail. With no retry/on_error policy on `publish_to_twitter`, a Twitter
401/403/429/5xx terminated the entire workflow run as failed. Add
`on_error: { strategy: skip, default_output: "twitter_publish_failed" }`
to the YAML so the run advances to `done` cleanly; the module already
surfaces categorized errors to Lark independently.

#2 — Twitter v2 native error shape: `ClassifyTwitterResponse` now
recognizes the third response shape NyxID can forward verbatim:
`{ "title": "...", "detail": "...", "errors": [...] }` (Twitter's
native problem-details for content-policy / duplicate-tweet rejections).
Falls through to `twitter_publish_rejected` with the Twitter `message`
text in the Lark surfacing so users read the actual rejection reason.

#1 — Duplicate tweet risk: documented in code comment that
`POST /2/tweets` has no server-side dedup; the social_media template
intentionally has no `retry` policy on this step, and `on_error: skip`
advances rather than retrying. Authors customizing the YAML must keep
this invariant.

#3 — Removed redundant `nyxClient!` null-forgiving (no-op cleanup).

#4 — Renamed `ChannelMetadataKeys.LarkProxySlug` →
`LarkOutboundProxySlug` (`channel.lark.outbound_proxy_slug`) to
disambiguate "Lark API surface" from "NyxID provider routing".

#5 — Added xml-doc on `TrySendLarkAsync` documenting the dual-scope
api-key dependency (key must carry both api-twitter AND api-lark-bot
entitlements) so future callers don't silently break Lark surfacing
when narrowing the key's scope.

#6 — Added `RequiredServiceSlugs` field to `SocialMediaTemplateSpec`
for parity with `DailyReportTemplateSpec`; `CreateSocialMediaAgentAsync`
now reads slugs from the spec instead of inlining the list.

Tests:
- 3 new `ClassifyTwitterResponse` tests for the Twitter native error
  shapes (errors-array, RFC-7807 title/detail-only, empty-object
  unexpected-shape).
- Existing social_media test now also asserts `strategy: skip` lands in
  the upserted YAML.
- 482 channel-runtime + 236 workflow.core tests pass; full solution
  builds with 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eanzhao added a commit that referenced this pull request Apr 27, 2026
…elper

Resolves three followup architecture-review points on PR #451:

### Channel.Runtime drops AI / Workflow direct deps (review #2)

`Channel.Runtime`'s csproj used to pull in `Aevatar.AI.Abstractions` and
`Aevatar.Workflow.Application.Abstractions` because of two files that
straddled the channel/AI and channel/workflow boundary:

- `ChannelContextMiddleware` (an `ILLMCallMiddleware` impl) — moved to
  `Aevatar.GAgents.NyxidChat`, which is the only package that needs it
  and already references `AI.Abstractions`. NyxidChat SCE registers it
  for the LLM call pipeline; Channel.Runtime SCE no longer touches
  `ILLMCallMiddleware`.
- `ChannelCardActionRouting` (builds `WorkflowResumeCommand`) — moved
  to `Aevatar.GAgents.NyxidChat` for the same reason. Its sole consumer
  (`ChannelConversationTurnRunner`) lives there too.

`Channel.Runtime.csproj` now references only `Channel.Abstractions`,
`Foundation.Abstractions`/`Core`, and the `CQRS.Projection.*` slice —
matching the "channel-agnostic flow + projection infrastructure"
charter from the RFC. Tests (`ChannelCardActionRoutingTests`) get the
extra `using Aevatar.GAgents.NyxidChat;`.

### Extract Elasticsearch projection-store toggle helper (review #4)

The `ResolveElasticsearchEnabled` + `BuildElasticsearchOptions` helper
pair was duplicated three times (Channel.Runtime / Device / Scheduled
SCEs) with slightly different log strings and `Console.Error.WriteLine`
output. Centralized into
`Aevatar.CQRS.Projection.Providers.Elasticsearch.DependencyInjection.ElasticsearchProjectionConfiguration`
with two static helpers:

- `IsEnabled(IConfiguration?, ILogger?, string? storeName)` — explicit
  flag → endpoints presence → false; logs a structured warning via
  `ILogger` (when supplied) instead of `Console.Error.WriteLine`.
- `BindOptions(IConfiguration)` — typed binder for
  `ElasticsearchProjectionDocumentStoreOptions`.

All three SCEs now call into this helper; per-package warning text is
parameterized via `storeName`. Section path
(`Projection:Document:Providers:Elasticsearch`) is exposed as a const
so future call sites stay in sync.

### Followup points acknowledged but deferred

- **Cross-package dep chain `NyxidChat → Authoring.Lark → Scheduled →
  Platform.Lark`** (review #1) — pre-existing arch debt that the split
  surfaced rather than introduced. Cleaner would be to invert via
  `IInboundFlowResolver` plug-ins so `ChannelConversationTurnRunner`
  doesn't reach into `AgentBuilderCardFlow` directly. Out of scope for
  the package split; tracking as a separate follow-up.
- **Tombstone compactor "central coordinator"** (review #3) —
  `Channel.Runtime` defines `ITombstoneCompactionTarget` but does not
  reference `Device` / `Scheduled` at the csproj level; per-package
  targets register themselves through DI. The plug-in pattern is
  intentional and keeps the DAG one-way.
- **`Scheduled` package name vs UserAgentCatalog content** (review #5)
  — `UserAgentCatalog` is the delivery-target registry that Scheduled
  agents read at execution time to route output, so co-locating it
  with `SkillRunnerGAgent` / `WorkflowAgentGAgent` is intentional.
  Renaming to `AgentCatalog` would split actors from their primary
  consumer; deferring.

473/473 ChannelRuntime.Tests pass; full slnx still only fails the same
two pre-existing Mainnet hosting `BindAsync on IStudioMemberService`
tests that reproduce on origin/dev.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eanzhao added a commit that referenced this pull request Apr 28, 2026
…r guard (#466)

PR #467 review nit #1: the constructor-parameter regex caught
`IUserAgentDeliveryTargetReader name,` but missed
`sp.GetService<IUserAgentDeliveryTargetReader>()`. Both AgentBuilderTool
and AgentDeliveryTargetTool already take IServiceProvider directly, so
the bypass was one line away. Add a second pattern matching
`Get(Required)?Service<IUserAgentDeliveryTargetReader>` in addition to
the constructor-parameter check; either pattern flags the file.

Verified locally: synthetic violation
`var r = sp.GetService<IUserAgentDeliveryTargetReader>()` in a class
implementing IAgentTool now fails the guard. Real tree (which doesn't
contain such a call) still returns ok.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 22, 2026
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.

2 participants