Skip to content

Commit d325a7f

Browse files
See USee U
authored andcommitted
feat(schema,server,plugin): add subagent live events, global executor wiring, and v2 plugin hooks
1 parent 8d404f6 commit d325a7f

5 files changed

Lines changed: 73 additions & 0 deletions

File tree

packages/plugin/src/v2/effect/context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import type { AgentHooks } from "./agent.js"
33
import type { AISDKHooks } from "./aisdk.js"
44
import type { CatalogHooks } from "./catalog.js"
55
import type { CommandHooks } from "./command.js"
6+
import type { Event } from "./event.js"
67
import type { IntegrationHooks } from "./integration.js"
78
import type { PluginDomain } from "./plugin.js"
89
import type { ReferenceHooks } from "./reference.js"
910
import type { SkillHooks } from "./skill.js"
11+
import type { ToolHooks } from "./tool.js"
1012
import type { Reload } from "./registration.js"
1113

1214
export interface PluginContext {
@@ -15,8 +17,10 @@ export interface PluginContext {
1517
readonly aisdk: AISDKHooks
1618
readonly catalog: CatalogHooks & Reload
1719
readonly command: CommandHooks & Reload
20+
readonly event: Event
1821
readonly integration: IntegrationHooks & Reload
1922
readonly plugin: PluginDomain
2023
readonly reference: ReferenceHooks & Reload
2124
readonly skill: SkillHooks & Reload
25+
readonly tool: ToolHooks
2226
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export type { PluginContext } from "./context.js"
2+
export type { Event, EventMap } from "./event.js"
3+
export type { ToolExecuteAfterEvent, ToolExecuteBeforeEvent, ToolHooks } from "./tool.js"
24
export { define } from "./plugin.js"
35
export type { Plugin } from "./plugin.js"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { Effect, Scope } from "effect"
2+
3+
export interface ToolExecuteBeforeEvent {
4+
readonly name: string
5+
readonly input: unknown
6+
readonly args: {
7+
readonly update: (input: unknown) => void
8+
}
9+
readonly deny: (reason: string) => void
10+
readonly skip: () => void
11+
}
12+
13+
export interface ToolExecuteAfterEvent {
14+
readonly name: string
15+
readonly input: unknown
16+
readonly output: unknown
17+
readonly context: {
18+
readonly add: (text: string) => void
19+
}
20+
}
21+
22+
export interface ToolHooks {
23+
hook(
24+
name: "execute.before",
25+
callback: (event: ToolExecuteBeforeEvent) => Effect.Effect<void>,
26+
): Effect.Effect<void, never, Scope.Scope>
27+
hook(
28+
name: "execute.after",
29+
callback: (event: ToolExecuteAfterEvent) => Effect.Effect<void>,
30+
): Effect.Effect<void, never, Scope.Scope>
31+
}

packages/schema/src/session-event.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,40 @@ export namespace Subagent {
561561
},
562562
})
563563
export type Completed = typeof Completed.Type
564+
565+
// Live coordination events for the event-decoupled subagent pipeline. The location-scoped
566+
// requester publishes Requested; the global executor (which owns SessionV2) drives the child
567+
// session and publishes Result. Keeping these live (non-durable) avoids a static dependency from
568+
// the location tool graph back through global SessionV2 -> LocationServiceMap, which would form a
569+
// layer cycle. Subagent restart recovery remains deferred with the rest of durable continuation.
570+
export const Requested = Event.define({
571+
type: "session.next.subagent.requested",
572+
schema: {
573+
...Base,
574+
subagentSessionID: SessionID,
575+
agent: Schema.String,
576+
task: Schema.String,
577+
context: Schema.String.pipe(optional),
578+
background: Schema.Boolean,
579+
mode: Schema.Union([Schema.Literal("new"), Schema.Literal("resume"), Schema.Literal("fork")]),
580+
},
581+
})
582+
export type Requested = typeof Requested.Type
583+
584+
export const Result = Event.define({
585+
type: "session.next.subagent.result",
586+
schema: {
587+
...Base,
588+
subagentSessionID: SessionID,
589+
status: Schema.Union([Schema.Literal("completed"), Schema.Literal("partial")]),
590+
output: Schema.String,
591+
tokens: Schema.Struct({
592+
input: Schema.Finite,
593+
output: Schema.Finite,
594+
}),
595+
},
596+
})
597+
export type Result = typeof Result.Type
564598
}
565599

566600
export namespace WireSchema {

packages/server/src/routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Credential } from "@opencode-ai/core/credential"
77
import { PermissionSaved } from "@opencode-ai/core/permission/saved"
88
import { PtyTicket } from "@opencode-ai/core/pty/ticket"
99
import { SessionV2 } from "@opencode-ai/core/session"
10+
import { SubagentExecutor } from "@opencode-ai/core/subagent/executor"
1011
import { SessionExecution } from "@opencode-ai/core/session/execution"
1112
import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
1213
import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
@@ -29,6 +30,7 @@ const applicationServices = LayerNode.group([
2930
httpClient,
3031
ToolOutputStore.cleanupNode,
3132
SessionV2.node,
33+
SubagentExecutor.node,
3234
PermissionSaved.node,
3335
PtyTicket.node,
3436
Credential.node,

0 commit comments

Comments
 (0)