feat(core): tool execute hooks, session instructions, synthetic endpoint
- V2 tool execute hooks: add `ctx.tool.execute.before/after` plugin API, core ToolHooks service, and registry wiring so hosted/local tool calls run registered before/after hooks; provider-executed calls are excluded. - Session synthetic endpoint: add `POST /api/session/:sessionID/synthetic` with text/description/metadata plus regenerated Promise/Effect/JS client surfaces. - SessionInstructions service: read tool discovers nearby AGENTS.md walking up to the Location root (exclusive) and injects them as durable synthetic instructions, with lazy history dedup of prior claims. - to-llm-message: stop forwarding synthetic message metadata to the model so bookkeeping annotations stay model-hidden. - schema changelog entry for synthetic metadata and the metadata leak fix.
This commit is contained in:
parent
d544ab4d91
commit
d972aa9d83
25 changed files with 893 additions and 116 deletions
|
|
@ -126,74 +126,84 @@ export type Endpoint4_9Input = {
|
|||
export type Endpoint4_9Output = EffectValue<ReturnType<RawClient["server.session"]["session.skill"]>>
|
||||
export type SessionSkillOperation<E = never> = (input: Endpoint4_9Input) => Effect.Effect<Endpoint4_9Output, E>
|
||||
|
||||
type Endpoint4_10Request = Parameters<RawClient["server.session"]["session.compact"]>[0]
|
||||
export type Endpoint4_10Input = { readonly sessionID: Endpoint4_10Request["params"]["sessionID"] }
|
||||
export type Endpoint4_10Output = EffectValue<ReturnType<RawClient["server.session"]["session.compact"]>>
|
||||
export type SessionCompactOperation<E = never> = (input: Endpoint4_10Input) => Effect.Effect<Endpoint4_10Output, E>
|
||||
type Endpoint4_10Request = Parameters<RawClient["server.session"]["session.synthetic"]>[0]
|
||||
export type Endpoint4_10Input = {
|
||||
readonly sessionID: Endpoint4_10Request["params"]["sessionID"]
|
||||
readonly text: Endpoint4_10Request["payload"]["text"]
|
||||
readonly description?: Endpoint4_10Request["payload"]["description"]
|
||||
readonly metadata?: Endpoint4_10Request["payload"]["metadata"]
|
||||
}
|
||||
export type Endpoint4_10Output = EffectValue<ReturnType<RawClient["server.session"]["session.synthetic"]>>
|
||||
export type SessionSyntheticOperation<E = never> = (input: Endpoint4_10Input) => Effect.Effect<Endpoint4_10Output, E>
|
||||
|
||||
type Endpoint4_11Request = Parameters<RawClient["server.session"]["session.wait"]>[0]
|
||||
type Endpoint4_11Request = Parameters<RawClient["server.session"]["session.compact"]>[0]
|
||||
export type Endpoint4_11Input = { readonly sessionID: Endpoint4_11Request["params"]["sessionID"] }
|
||||
export type Endpoint4_11Output = EffectValue<ReturnType<RawClient["server.session"]["session.wait"]>>
|
||||
export type SessionWaitOperation<E = never> = (input: Endpoint4_11Input) => Effect.Effect<Endpoint4_11Output, E>
|
||||
export type Endpoint4_11Output = EffectValue<ReturnType<RawClient["server.session"]["session.compact"]>>
|
||||
export type SessionCompactOperation<E = never> = (input: Endpoint4_11Input) => Effect.Effect<Endpoint4_11Output, E>
|
||||
|
||||
type Endpoint4_12Request = Parameters<RawClient["server.session"]["session.revert.stage"]>[0]
|
||||
export type Endpoint4_12Input = {
|
||||
readonly sessionID: Endpoint4_12Request["params"]["sessionID"]
|
||||
readonly messageID: Endpoint4_12Request["payload"]["messageID"]
|
||||
readonly files?: Endpoint4_12Request["payload"]["files"]
|
||||
type Endpoint4_12Request = Parameters<RawClient["server.session"]["session.wait"]>[0]
|
||||
export type Endpoint4_12Input = { readonly sessionID: Endpoint4_12Request["params"]["sessionID"] }
|
||||
export type Endpoint4_12Output = EffectValue<ReturnType<RawClient["server.session"]["session.wait"]>>
|
||||
export type SessionWaitOperation<E = never> = (input: Endpoint4_12Input) => Effect.Effect<Endpoint4_12Output, E>
|
||||
|
||||
type Endpoint4_13Request = Parameters<RawClient["server.session"]["session.revert.stage"]>[0]
|
||||
export type Endpoint4_13Input = {
|
||||
readonly sessionID: Endpoint4_13Request["params"]["sessionID"]
|
||||
readonly messageID: Endpoint4_13Request["payload"]["messageID"]
|
||||
readonly files?: Endpoint4_13Request["payload"]["files"]
|
||||
}
|
||||
export type Endpoint4_12Output = EffectValue<ReturnType<RawClient["server.session"]["session.revert.stage"]>>["data"]
|
||||
export type SessionRevertStageOperation<E = never> = (input: Endpoint4_12Input) => Effect.Effect<Endpoint4_12Output, E>
|
||||
export type Endpoint4_13Output = EffectValue<ReturnType<RawClient["server.session"]["session.revert.stage"]>>["data"]
|
||||
export type SessionRevertStageOperation<E = never> = (input: Endpoint4_13Input) => Effect.Effect<Endpoint4_13Output, E>
|
||||
|
||||
type Endpoint4_13Request = Parameters<RawClient["server.session"]["session.revert.clear"]>[0]
|
||||
export type Endpoint4_13Input = { readonly sessionID: Endpoint4_13Request["params"]["sessionID"] }
|
||||
export type Endpoint4_13Output = EffectValue<ReturnType<RawClient["server.session"]["session.revert.clear"]>>
|
||||
export type SessionRevertClearOperation<E = never> = (input: Endpoint4_13Input) => Effect.Effect<Endpoint4_13Output, E>
|
||||
|
||||
type Endpoint4_14Request = Parameters<RawClient["server.session"]["session.revert.commit"]>[0]
|
||||
type Endpoint4_14Request = Parameters<RawClient["server.session"]["session.revert.clear"]>[0]
|
||||
export type Endpoint4_14Input = { readonly sessionID: Endpoint4_14Request["params"]["sessionID"] }
|
||||
export type Endpoint4_14Output = EffectValue<ReturnType<RawClient["server.session"]["session.revert.commit"]>>
|
||||
export type SessionRevertCommitOperation<E = never> = (input: Endpoint4_14Input) => Effect.Effect<Endpoint4_14Output, E>
|
||||
export type Endpoint4_14Output = EffectValue<ReturnType<RawClient["server.session"]["session.revert.clear"]>>
|
||||
export type SessionRevertClearOperation<E = never> = (input: Endpoint4_14Input) => Effect.Effect<Endpoint4_14Output, E>
|
||||
|
||||
type Endpoint4_15Request = Parameters<RawClient["server.session"]["session.context"]>[0]
|
||||
type Endpoint4_15Request = Parameters<RawClient["server.session"]["session.revert.commit"]>[0]
|
||||
export type Endpoint4_15Input = { readonly sessionID: Endpoint4_15Request["params"]["sessionID"] }
|
||||
export type Endpoint4_15Output = EffectValue<ReturnType<RawClient["server.session"]["session.context"]>>["data"]
|
||||
export type SessionContextOperation<E = never> = (input: Endpoint4_15Input) => Effect.Effect<Endpoint4_15Output, E>
|
||||
export type Endpoint4_15Output = EffectValue<ReturnType<RawClient["server.session"]["session.revert.commit"]>>
|
||||
export type SessionRevertCommitOperation<E = never> = (input: Endpoint4_15Input) => Effect.Effect<Endpoint4_15Output, E>
|
||||
|
||||
type Endpoint4_16Request = Parameters<RawClient["server.session"]["session.history"]>[0]
|
||||
export type Endpoint4_16Input = {
|
||||
readonly sessionID: Endpoint4_16Request["params"]["sessionID"]
|
||||
readonly limit?: Endpoint4_16Request["query"]["limit"]
|
||||
readonly after?: Endpoint4_16Request["query"]["after"]
|
||||
}
|
||||
export type Endpoint4_16Output = EffectValue<ReturnType<RawClient["server.session"]["session.history"]>>
|
||||
export type SessionHistoryOperation<E = never> = (input: Endpoint4_16Input) => Effect.Effect<Endpoint4_16Output, E>
|
||||
type Endpoint4_16Request = Parameters<RawClient["server.session"]["session.context"]>[0]
|
||||
export type Endpoint4_16Input = { readonly sessionID: Endpoint4_16Request["params"]["sessionID"] }
|
||||
export type Endpoint4_16Output = EffectValue<ReturnType<RawClient["server.session"]["session.context"]>>["data"]
|
||||
export type SessionContextOperation<E = never> = (input: Endpoint4_16Input) => Effect.Effect<Endpoint4_16Output, E>
|
||||
|
||||
type Endpoint4_17Request = Parameters<RawClient["server.session"]["session.events"]>[0]
|
||||
type Endpoint4_17Request = Parameters<RawClient["server.session"]["session.history"]>[0]
|
||||
export type Endpoint4_17Input = {
|
||||
readonly sessionID: Endpoint4_17Request["params"]["sessionID"]
|
||||
readonly limit?: Endpoint4_17Request["query"]["limit"]
|
||||
readonly after?: Endpoint4_17Request["query"]["after"]
|
||||
}
|
||||
export type Endpoint4_17Output = StreamValue<EffectValue<ReturnType<RawClient["server.session"]["session.events"]>>>
|
||||
export type SessionEventsOperation<E = never> = (input: Endpoint4_17Input) => Stream.Stream<Endpoint4_17Output, E>
|
||||
export type Endpoint4_17Output = EffectValue<ReturnType<RawClient["server.session"]["session.history"]>>
|
||||
export type SessionHistoryOperation<E = never> = (input: Endpoint4_17Input) => Effect.Effect<Endpoint4_17Output, E>
|
||||
|
||||
type Endpoint4_18Request = Parameters<RawClient["server.session"]["session.interrupt"]>[0]
|
||||
export type Endpoint4_18Input = { readonly sessionID: Endpoint4_18Request["params"]["sessionID"] }
|
||||
export type Endpoint4_18Output = EffectValue<ReturnType<RawClient["server.session"]["session.interrupt"]>>
|
||||
export type SessionInterruptOperation<E = never> = (input: Endpoint4_18Input) => Effect.Effect<Endpoint4_18Output, E>
|
||||
|
||||
type Endpoint4_19Request = Parameters<RawClient["server.session"]["session.background"]>[0]
|
||||
export type Endpoint4_19Input = { readonly sessionID: Endpoint4_19Request["params"]["sessionID"] }
|
||||
export type Endpoint4_19Output = EffectValue<ReturnType<RawClient["server.session"]["session.background"]>>
|
||||
export type SessionBackgroundOperation<E = never> = (input: Endpoint4_19Input) => Effect.Effect<Endpoint4_19Output, E>
|
||||
|
||||
type Endpoint4_20Request = Parameters<RawClient["server.session"]["session.message"]>[0]
|
||||
export type Endpoint4_20Input = {
|
||||
readonly sessionID: Endpoint4_20Request["params"]["sessionID"]
|
||||
readonly messageID: Endpoint4_20Request["params"]["messageID"]
|
||||
type Endpoint4_18Request = Parameters<RawClient["server.session"]["session.events"]>[0]
|
||||
export type Endpoint4_18Input = {
|
||||
readonly sessionID: Endpoint4_18Request["params"]["sessionID"]
|
||||
readonly after?: Endpoint4_18Request["query"]["after"]
|
||||
}
|
||||
export type Endpoint4_20Output = EffectValue<ReturnType<RawClient["server.session"]["session.message"]>>["data"]
|
||||
export type SessionMessageOperation<E = never> = (input: Endpoint4_20Input) => Effect.Effect<Endpoint4_20Output, E>
|
||||
export type Endpoint4_18Output = StreamValue<EffectValue<ReturnType<RawClient["server.session"]["session.events"]>>>
|
||||
export type SessionEventsOperation<E = never> = (input: Endpoint4_18Input) => Stream.Stream<Endpoint4_18Output, E>
|
||||
|
||||
type Endpoint4_19Request = Parameters<RawClient["server.session"]["session.interrupt"]>[0]
|
||||
export type Endpoint4_19Input = { readonly sessionID: Endpoint4_19Request["params"]["sessionID"] }
|
||||
export type Endpoint4_19Output = EffectValue<ReturnType<RawClient["server.session"]["session.interrupt"]>>
|
||||
export type SessionInterruptOperation<E = never> = (input: Endpoint4_19Input) => Effect.Effect<Endpoint4_19Output, E>
|
||||
|
||||
type Endpoint4_20Request = Parameters<RawClient["server.session"]["session.background"]>[0]
|
||||
export type Endpoint4_20Input = { readonly sessionID: Endpoint4_20Request["params"]["sessionID"] }
|
||||
export type Endpoint4_20Output = EffectValue<ReturnType<RawClient["server.session"]["session.background"]>>
|
||||
export type SessionBackgroundOperation<E = never> = (input: Endpoint4_20Input) => Effect.Effect<Endpoint4_20Output, E>
|
||||
|
||||
type Endpoint4_21Request = Parameters<RawClient["server.session"]["session.message"]>[0]
|
||||
export type Endpoint4_21Input = {
|
||||
readonly sessionID: Endpoint4_21Request["params"]["sessionID"]
|
||||
readonly messageID: Endpoint4_21Request["params"]["messageID"]
|
||||
}
|
||||
export type Endpoint4_21Output = EffectValue<ReturnType<RawClient["server.session"]["session.message"]>>["data"]
|
||||
export type SessionMessageOperation<E = never> = (input: Endpoint4_21Input) => Effect.Effect<Endpoint4_21Output, E>
|
||||
|
||||
export interface SessionApi<E = never> {
|
||||
readonly list: SessionListOperation<E>
|
||||
|
|
@ -206,6 +216,7 @@ export interface SessionApi<E = never> {
|
|||
readonly rename: SessionRenameOperation<E>
|
||||
readonly prompt: SessionPromptOperation<E>
|
||||
readonly skill: SessionSkillOperation<E>
|
||||
readonly synthetic: SessionSyntheticOperation<E>
|
||||
readonly compact: SessionCompactOperation<E>
|
||||
readonly wait: SessionWaitOperation<E>
|
||||
readonly revertStage: SessionRevertStageOperation<E>
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@ export type { PluginContext } from "./context.js"
|
|||
export { define } from "./plugin.js"
|
||||
export type { Plugin } from "./plugin.js"
|
||||
export * as Tool from "./tool.js"
|
||||
export type { ToolDomain } from "./tool.js"
|
||||
export type { ToolDomain, ToolExecuteBeforeEvent, ToolExecuteAfterEvent } from "./tool.js"
|
||||
export type { SessionDomain } from "./runtime.js"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
export * as Tool from "./tool.js"
|
||||
|
||||
import { ToolDefinition, ToolFailure, ToolOutput, type ToolCall } from "@opencode-ai/llm"
|
||||
import { ToolDefinition, ToolFailure, ToolOutput, type ToolCall, type ToolResultValue } from "@opencode-ai/llm"
|
||||
import { Agent } from "@opencode-ai/schema/agent"
|
||||
import { Session } from "@opencode-ai/schema/session"
|
||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||
import { Effect, JsonSchema, Schema, type Scope } from "effect"
|
||||
import type { Hooks } from "./registration.js"
|
||||
|
||||
export interface Context {
|
||||
readonly sessionID: Session.ID
|
||||
|
|
@ -213,6 +214,28 @@ function toJsonSchema(schema: Schema.Top): JsonSchema.JsonSchema {
|
|||
return { ...document.schema, $defs: document.definitions }
|
||||
}
|
||||
|
||||
export interface ToolExecuteBeforeEvent {
|
||||
readonly tool: string
|
||||
readonly sessionID: Session.ID
|
||||
readonly agent: Agent.ID
|
||||
readonly assistantMessageID: SessionMessage.ID
|
||||
readonly toolCallID: string
|
||||
input: unknown
|
||||
}
|
||||
|
||||
export interface ToolExecuteAfterEvent {
|
||||
readonly tool: string
|
||||
readonly sessionID: Session.ID
|
||||
readonly agent: Agent.ID
|
||||
readonly assistantMessageID: SessionMessage.ID
|
||||
readonly toolCallID: string
|
||||
readonly input: unknown
|
||||
result: ToolResultValue
|
||||
output?: ToolOutput
|
||||
outputPaths?: ReadonlyArray<string>
|
||||
}
|
||||
|
||||
export interface ToolDomain {
|
||||
readonly register: (tools: Readonly<Record<string, AnyTool>>) => Effect.Effect<void, RegistrationError, Scope.Scope>
|
||||
readonly execute: Hooks<{ before: ToolExecuteBeforeEvent; after: ToolExecuteAfterEvent }>
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue