Skip to content

Commit f2e798d

Browse files
authored
Merge branch 'main' into dependabot/github_actions/actions/create-github-app-token-3.2.0
2 parents 2e954a7 + 1a3b51a commit f2e798d

1,489 files changed

Lines changed: 68844 additions & 51005 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/agent-core-dev/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ End-to-end procedures that span the stages. Reach for these before reading the s
3333

3434
## Stages
3535

36-
- [Stage 1 — Orient](orient.md): the DI black box (identity / dependencies / lifetime), the four `LifecycleScope` tiers and visibility, and the no-comment convention. Read before touching business code.
36+
- [Stage 1 — Orient](orient.md): the DI black box (identity / dependencies / lifetime), the three `LifecycleScope` tiers and visibility, the separate workspace program lifetime, and the no-comment convention. Read before touching business code.
3737
- [Stage 2 — Design a service](design.md): pick a scope, split a domain across scopes, choose a calling style (direct call vs event vs hook), and direct dependencies. Decide *where things live and who knows whom* before coding.
3838
- Topic: [Domain boundaries vs Scope](domain-boundaries.md) — keep `session` / `agent` / `turn` from becoming god objects; data-ownership test and their split conclusions.
3939
- Topic: [Persistence layering](persistence.md) — the three-layer `Store → Storage → backend` model, naming Stores by access pattern, and which layer business code should depend on.

.agents/skills/agent-core-dev/align.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ v1 is a **VSCode-style singleton container**: services self-register with `regis
1414
|---|---|---|
1515
| Registration | `registerSingleton(IX, X, InstantiationType.Delayed)` | `registerScopedService(LifecycleScope.X, IX, X, ScopeActivation.OnDemand, 'domain')` |
1616
| DI import | `from '../../di'` | `from '#/_base/di/scope'` / `'#/_base/di/instantiation'` / `'#/_base/di/lifecycle'` |
17-
| Lifetime | implicit singleton-per-container | explicit `LifecycleScope` (App/Workspace/Session/Agent) — see orient.md |
17+
| Lifetime | implicit singleton-per-container | explicit `LifecycleScope` (App/Session/Agent); workspace resources use the separate `WorkspaceInstance` / `Program` lifetime — see orient.md |
1818
| Domain granularity | coarse (`session`, `tool`, `loop`) | fine, split by scope + responsibility |
1919
| Test import | `from '@pymodel/agent-core/di/test'` | `from '#/_base/di/test'` |
2020
| Resolve SUT in tests | `ix.createInstance(Impl)` (common) | `ix.get(IX)` by interface — see test.md |

.agents/skills/agent-core-dev/design.md

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ A Service = a bundle of **state** + a set of **behaviors**, bound to a **lifetim
1717

1818
> Scope = the identity + lifetime of the owned state.
1919
20-
| Scope | State identity (keyed by) | Lifetime |
20+
| Owner | State identity (keyed by) | Lifetime |
2121
|---|---|---|
22-
| `App` | none (single global instance) | the process |
23-
| `Workspace` | `workspaceId` | one workspace handler (materialized once per workspace, never closed — dies with the process) |
24-
| `Session` | `sessionId` | one session |
25-
| `Agent` | `agentId` | one agent |
22+
| `LifecycleScope.App` | none (single global instance) | the process |
23+
| workspace `Program` | `workspaceId` | one materialized workspace instance or runtime generation |
24+
| `LifecycleScope.Session` | `sessionId` | one session |
25+
| `LifecycleScope.Agent` | `agentId` | one agent |
2626

2727
### Decision tree
2828

@@ -34,7 +34,7 @@ A Service = a bundle of **state** + a set of **behaviors**, bound to a **lifetim
3434
**Q2. What is the identity of that state?**
3535

3636
- one global instance → **`App`**
37-
- one per workspace (shared by every session of that workspace) → **`Workspace`**
37+
- one per workspace (shared by every session of that workspace) → a program-owned **workspace component**
3838
- one per session → **`Session`**
3939
- one per agent → **`Agent`**
4040
- a mix (a global registry *and* per-instance state) → **split it** (see §3).
@@ -72,7 +72,7 @@ The standard split is "global registry / factory" + "per-instance":
7272
| Tier | Role | Naming tends to |
7373
|---|---|---|
7474
| `App` | global registry / catalog / factory — knows "all of them" and how to create one | `XxxStore` / `XxxRegistry` / `XxxCatalog` |
75-
| `Workspace` / `Session` / `Agent` | one instance — only the state of "this one" | `XxxService` / `IWorkspaceXxx` / `ISessionXxx` / `IAgentXxx` |
75+
| workspace program / `Session` / `Agent` | one instance — only the state of "this one" | `XxxService` / `IWorkspaceXxx` / `ISessionXxx` / `IAgentXxx` |
7676

7777
Canonical splits in the codebase:
7878

@@ -179,13 +179,13 @@ Two standing red lines on top of that:
179179
After the checklist, render the result as a plaintext tree — the deliverable reviewers read. Keep it in the design doc or PR description.
180180

181181
```text
182-
domain: `<name>` (owning scope: <Scope>)
182+
domain: `<name>` (owning lifetime: <Owner>)
183183
├─ serves (who uses me) tag = HOW they reach me
184184
│ ├─ (inject) <ConsumerDomain> @<Scope> — <what they use me for>
185185
│ └─ (accessor) <ConsumerDomain> @<Scope> — <what they use me for>
186186
├─ exposes (interfaces I provide, by scope)
187187
│ ├─ App : <IXxxRegistry> — <role>
188-
│ ├─ Workspace : <IWorkspaceXxx> — <role>
188+
│ ├─ Workspace program : <IWorkspaceXxx> — <role>
189189
│ ├─ Session : <ISessionXxx> — <role>
190190
│ └─ Agent : <IAgentXxx> — <role>
191191
└─ depends (what I inject) tag = calling style
@@ -225,52 +225,30 @@ Read it as:
225225
Worked example — `sessionLifecycle`:
226226

227227
```text
228-
domain: `sessionLifecycle` (owning scope: Workspace)
229-
├─ serves (who uses me)
230-
│ ├─ (inject) — (none)
231-
│ └─ (accessor)
232-
│ ├─ sessionLegacy @App(edge) — v1-compatible create/fork/archive/…
233-
│ └─ gateway / rpc @App(edge) — native v2 session lifecycle actions
234-
├─ exposes (interfaces I provide, by scope)
235-
│ ├─ Workspace : ISessionLifecycleService — owns this workspace's live session scope tree
236-
│ ├─ Session : — — (per-session state lives in sessionMetadata / agentLifecycle / …)
237-
│ └─ Agent : — — (per-agent state lives in agentLifecycle)
238-
└─ depends (what I inject)
239-
├─ workspaceContext @Workspace seed — handler identity + persistence scope
240-
├─ bootstrap @App direct — addresses session storage
241-
├─ hostEnvironment @App direct — gates scope creation on the probe
242-
├─ sessionIndex @App direct — persisted read model for cold resumes
243-
├─ storage @App direct — atomic docs + append logs
244-
├─ workspaceDirs / workspaceSkillCatalog / workspaceMcp / …
245-
│ @Workspace direct — the handler's shared resource services
246-
└─ event @App direct — broadcasts session-level facts (e.g. archived)
247-
```
248-
249-
Cross-scope borrow for `sessionLifecycle`:
250-
251-
```text
252-
App scope
253-
WorkspaceLifecycleService ──holds──► IScopeHandle(workspaceId) (one per live handler)
254-
255-
│ accessor.get(ISessionLifecycleService)
256-
│ └── resolve runs inside the Workspace scope
257-
258-
Workspace scope (workspaceId)
259-
SessionLifecycleService ──holds──► IScopeHandle(sessionId)
260-
261-
│ accessor.get(ISessionMetadata) …
262-
│ └── resolve runs inside the Session scope
263-
264-
Session scope (sessionId)
265-
sessionMetadata / agentLifecycle / … ← per-session services live here
228+
domain: `sessionLifecycle` (owning lifetime: workspace Program)
229+
├─ serves
230+
│ └─ SessionManager @App — creates, resumes, forks, closes, and archives sessions
231+
├─ exposes
232+
│ └─ workspace Program : ISessionLifecycleService — owns this controller's live Session scopes
233+
└─ depends
234+
├─ workspace context/resources @Program direct — identity, fs, dirs, skills, MCP, profiles
235+
└─ App services @App direct — persistence, config, telemetry, events
266236
```
267237

268-
How the three lenses shaped it:
238+
The App-scoped `IWorkspaceInstanceManager` owns `WorkspaceInstance` objects. Each instance owns a
239+
`Program`. The Program constructs workspace resources and creates a `SessionLifecycleService`
240+
with them. That service creates real `LifecycleScope.Session` children, and each session creates
241+
`LifecycleScope.Agent` children. There is no workspace `IScopeHandle` and no Workspace value in
242+
`LifecycleScope`.
269243

270-
- **Scope (§2)** → the live registry of one workspace's session scopes is per-handler, so it is Workspace-scoped; the process-wide handler registry lives in the App-scoped `workspaceLifecycle`; per-session data stays in Session-scoped services, reached through the handle's `accessor`.
271-
- **Dependency direction (§5)**`sessionLifecycle` is consumed by the edge via `accessor` borrows; it never imports the edge. Every downward arrow lands on a peer or a more foundational Service.
272-
- **Extension points (§4)** → new per-session behavior plugs into the Session-scoped services (`sessionMetadata`, `agentLifecycle`, `sessionActivity`); new transports stay at the edge. Neither edits `sessionLifecycle`.
244+
How the three lenses shape it:
273245

246+
- **Lifetime (§2)** → workspace state belongs to the Program; per-session state belongs to Session
247+
scopes; per-agent state belongs to Agent scopes.
248+
- **Dependency direction (§5)** → the Program receives App dependencies and passes workspace
249+
resources into the session controller; business code does not import the edge.
250+
- **Extension points (§4)** → new per-session behavior belongs in Session-scoped services; new
251+
transports stay at the edge.
274252
For a multi-scope split, the `exposes` block fills more than one scope — see the `records` pattern in §3.
275253

276254
## Red lines (this stage)

.agents/skills/agent-core-dev/domain-boundaries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ The `session` domain owns only Session-level identity, metadata, lifecycle comma
8282
|---|---|---|
8383
| `sessionId`, `workspaceId`, `sessionDir`, `metaScope` | `sessionContext` | Seeded facts; no IO |
8484
| `SessionMeta` | `sessionMetadata` | Durable atomic document; entity-like |
85-
| Open session scope registry | `sessionLifecycle` | Workspace-scope live handles, one registry per workspace handler (the process-wide handler registry is `workspaceLifecycle`); not the persisted entity table |
85+
| Open session scope registry | `sessionLifecycle` | Program-owned controller with live Session handles; each workspace Program creates it from current workspace resources; not the persisted entity table |
8686
| Session commands such as `archive()` | `session` | Orchestrates metadata, agent teardown, and events |
8787
| Persisted session list / get / count | `sessionIndex` | Backend-neutral read model |
8888
| Running / idle / awaiting status | `sessionActivity` | Derived from interactions and active turns; owns no state |

.agents/skills/agent-core-dev/edge-exposure.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ The transport (`/api/v2` over HTTP + WS) lives in the **edge** layer (`gateway`/
1313

1414
## 1. The edge model
1515

16-
Four scopes, four URL shapes, one dispatcher:
16+
Three DI scopes, four resource address shapes:
1717

1818
```text
1919
GET|POST /api/v2/:sa Core
20-
GET|POST /api/v2/workspace/:workspace_id/:sa Workspace
20+
GET|POST /api/v2/workspace/:workspace_id/:sa Workspace program
2121
GET|POST /api/v2/session/:session_id/:sa Session
2222
GET|POST /api/v2/session/:session_id/agent/:agent_id/:sa Agent
2323
```
@@ -29,7 +29,7 @@ GET|POST /api/v2/session/:session_id/agent/:agent_id/:sa Agent
2929
- `:action` is the method. `GET` for reads, `POST` for writes.
3030
- Body = the method's single argument (JSON), omitted for no-arg.
3131
- Response = the project envelope `{ code, msg, data, request_id, details? }`.
32-
- The dispatcher resolves the **scope** from the URL, the **Service** from an `actionMap`, calls the method, wraps the result.
32+
- The original dispatcher design resolves an address from the URL, selects a Service from an `actionMap`, calls the method, and wraps the result. A workspace URL identifies a program-owned resource; Workspace is not a `LifecycleScope` value.
3333

3434
```ts
3535
// actionMap — the allowlist; hides internal domain names.

.agents/skills/agent-core-dev/orient.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,28 @@ When writing business code you declare three things; the container handles the r
1212

1313
Classes talk only to interfaces and never care how an implementation is constructed.
1414

15-
## The four `LifecycleScope` tiers
15+
## The three `LifecycleScope` tiers
1616

17-
Lifetimes form a tree, from longest to shortest:
17+
DI lifetimes form a tree, from longest to shortest:
1818

1919
```text
2020
App process-wide, single global instance
21-
└── Workspace one workspace handler (a materialized workspace root)
22-
└── Session one session
23-
└── Agent one agent
21+
└── Session one session
22+
└── Agent one agent
2423
```
2524

2625
```ts
27-
// src/app/scopes.ts — the business layer declares the tiers and their order;
28-
// the DI kernel only knows opaque string kinds plus the declared topology.
2926
export enum LifecycleScope {
3027
App = 'app',
31-
Workspace = 'workspace',
3228
Session = 'session',
3329
Agent = 'agent',
3430
}
3531
```
3632

33+
Workspace resources have a separate lifetime. The App-scoped `IWorkspaceInstanceManager`
34+
materializes one `WorkspaceInstance` per workspace. Its `Program` constructs and disposes the
35+
workspace services. `Workspace` is a domain identity, not a `LifecycleScope` value.
36+
3737
- Later in the topology = shorter life = closer to a leaf.
3838
- "Singleton" means **one per scope**: `ILogService` is global once; each `Session` scope has its own `ISessionMetadata`.
3939
- `kind` must advance along the declared topology in the parent→child direction.
@@ -49,7 +49,7 @@ A child scope sees its ancestors; a parent never sees its children. Resolution w
4949
5050
### Disposal order
5151

52-
Deterministic: **child scopes die first; within one scope, teardown runs in strict reverse registration order, one entry at a time.** The mechanism is the Ledger (`src/_base/lifecycle/`): ordered effect bookkeeping, dual-track (sync + async disposers), serial reverse-order teardown (never parallel), with the teardown reason (`'scope-close' | 'cascade' | 'unload'`) passed through to every disposer. `Disposable` / `DisposableStore` (`src/_base/di/lifecycle.ts`) delegate to it — "reverse construction order" is a Ledger property, not a container convention. Business code declares which tier it lives in and never disposes by hand.
52+
Deterministic: **child scopes die first; within one scope, teardown runs in strict reverse registration order, one entry at a time.** The mechanism is the Ledger (`src/_base/lifecycle/`): ordered effect bookkeeping, dual-track (sync + async disposers), serial reverse-order teardown (never parallel), with the teardown reason (`'scope-close' | 'cascade' | 'unload'`) passed through to every disposer. `Disposable` / `DisposableStore` (`src/_base/di/lifecycle.ts`) delegate to it — "reverse construction order" is a Ledger property, not a container convention. Scoped business code declares its DI tier. Workspace programs explicitly own their manually constructed resources.
5353

5454
## Dynamic DI: units and cascades
5555

@@ -68,10 +68,10 @@ There is no domain-layer numbering — a domain may import any other domain, gui
6868

6969
## Comment convention
7070

71-
`packages/agent-core-v2/AGENTS.md` bans comments: no file headers, no section banners, no statement-level narration — the code is the source of truth. The only exception is JSDoc attached to exported symbols, which flows into the generated `.d.ts` and the consumers' IDE hover. Tooling directives (`eslint-disable`, `@ts-expect-error`, …) are banned too: fix the underlying lint/type problem instead, and put negative type-safety cases in compiler-asserted fixtures. Scope is carried by the filename: `workspace*.ts` = Workspace, `session*.ts` = Session, `agent*.ts` = Agent, no prefix = App (see service-authoring.md).
71+
`packages/agent-core-v2/AGENTS.md` bans comments entirely: no file headers, no section banners, no statement-level narration, no JSDoc (not even on exported symbols) — the code is the source of truth. The only exception is a load-bearing lint-suppression directive (`oxlint-disable` / `eslint-disable`) for a deliberate pattern; other tooling directives (`@ts-expect-error`, …) are banned: fix the underlying lint/type problem instead, and put negative type-safety cases in compiler-asserted fixtures. DI scope is carried by registration: `LifecycleScope.App`, `LifecycleScope.Session`, or `LifecycleScope.Agent`. A `workspace*` filename marks workspace-domain ownership, not a DI scope (see service-authoring.md).
7272

7373
## Red lines (this stage)
7474

7575
- Import via the `#/...` alias (mapped to `src/`); never reach into another domain's internals by relative path.
7676
- Short-lived may inject long-lived; never the reverse.
77-
- No comments — not file headers, not beside statements; exported-symbol JSDoc is the only exception.
77+
- No comments — not file headers, not beside statements, not JSDoc; a load-bearing lint-suppression directive is the only exception.

0 commit comments

Comments
 (0)