mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-22 19:55:11 +00:00
core: enable real-time tool progress updates during execution
Add session.next.tool.progress event so users can see live status from long-running tools instead of waiting for completion. Consolidate tool state metadata into a unified 'details' field for consistent display.
This commit is contained in:
parent
91938e2934
commit
97685d5ed1
4 changed files with 51 additions and 47 deletions
|
|
@ -380,7 +380,6 @@ export const layer: Layer.Layer<
|
|||
SyncEvent.run(SessionEvent.Tool.Success.Sync, {
|
||||
sessionID: ctx.sessionID,
|
||||
callID: value.toolCallId,
|
||||
title: value.output.title,
|
||||
output: value.output.output,
|
||||
attachments: value.output.attachments?.map((item: MessageV2.FilePart) => ({
|
||||
uri: item.url,
|
||||
|
|
@ -396,9 +395,9 @@ export const layer: Layer.Layer<
|
|||
}
|
||||
: {}),
|
||||
})),
|
||||
details: value.output.metadata,
|
||||
provider: {
|
||||
executed: toolCall?.part.metadata?.providerExecuted === true,
|
||||
metadata: value.output.metadata,
|
||||
},
|
||||
timestamp: DateTime.makeUnsafe(Date.now()),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -169,6 +169,16 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
|
|||
)
|
||||
}
|
||||
},
|
||||
"session.next.tool.progress": (event) => {
|
||||
if (currentAssistant) {
|
||||
adapter.updateAssistant(
|
||||
produce(currentAssistant, (draft) => {
|
||||
const match = latestTool(draft, event.data.callID)
|
||||
if (match && match.state.status === "running") match.state.details = event.data.details
|
||||
}),
|
||||
)
|
||||
}
|
||||
},
|
||||
"session.next.tool.success": (event) => {
|
||||
if (currentAssistant) {
|
||||
adapter.updateAssistant(
|
||||
|
|
@ -179,8 +189,7 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
|
|||
status: "completed",
|
||||
input: match.state.input,
|
||||
output: event.data.output ?? "",
|
||||
title: event.data.title,
|
||||
metadata: event.metadata ?? {},
|
||||
details: event.data.details,
|
||||
attachments: [...(event.data.attachments ?? [])],
|
||||
}
|
||||
}
|
||||
|
|
@ -198,7 +207,6 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
|
|||
status: "error",
|
||||
error: event.data.error,
|
||||
input: match.state.input,
|
||||
metadata: event.metadata ?? {},
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -62,16 +62,14 @@ export class ToolStatePending extends Schema.Class<ToolStatePending>("Session.En
|
|||
export class ToolStateRunning extends Schema.Class<ToolStateRunning>("Session.Entry.ToolState.Running")({
|
||||
status: Schema.Literal("running"),
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
title: Schema.String.pipe(Schema.optional),
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
details: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
}) {}
|
||||
|
||||
export class ToolStateCompleted extends Schema.Class<ToolStateCompleted>("Session.Entry.ToolState.Completed")({
|
||||
status: Schema.Literal("completed"),
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
output: Schema.String,
|
||||
title: Schema.String,
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown),
|
||||
details: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
attachments: SessionEvent.FileAttachment.pipe(Schema.Array, Schema.optional),
|
||||
}) {}
|
||||
|
||||
|
|
@ -79,7 +77,7 @@ export class ToolStateError extends Schema.Class<ToolStateError>("Session.Entry.
|
|||
status: Schema.Literal("error"),
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
error: Schema.String,
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
details: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
}) {}
|
||||
|
||||
export const ToolState = Schema.Union([ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]).pipe(
|
||||
|
|
|
|||
|
|
@ -16,12 +16,16 @@ export const Source = Schema.Struct({
|
|||
})
|
||||
export type Source = Schema.Schema.Type<typeof Source>
|
||||
|
||||
const Base = {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
}
|
||||
|
||||
export const Prompted = Event.define({
|
||||
type: "session.next.prompted",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
prompt: Prompt,
|
||||
},
|
||||
})
|
||||
|
|
@ -31,8 +35,7 @@ export const Synthetic = Event.define({
|
|||
type: "session.next.synthetic",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
text: Schema.String,
|
||||
},
|
||||
})
|
||||
|
|
@ -43,8 +46,7 @@ export namespace Step {
|
|||
type: "session.next.step.started",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
model: Schema.Struct({
|
||||
id: Schema.String,
|
||||
providerID: Schema.String,
|
||||
|
|
@ -58,8 +60,7 @@ export namespace Step {
|
|||
type: "session.next.step.ended",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
reason: Schema.String,
|
||||
cost: Schema.Number,
|
||||
tokens: Schema.Struct({
|
||||
|
|
@ -81,8 +82,7 @@ export namespace Text {
|
|||
type: "session.next.text.started",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
},
|
||||
})
|
||||
export type Started = Schema.Schema.Type<typeof Started>
|
||||
|
|
@ -91,8 +91,7 @@ export namespace Text {
|
|||
type: "session.next.text.delta",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
delta: Schema.String,
|
||||
},
|
||||
})
|
||||
|
|
@ -102,8 +101,7 @@ export namespace Text {
|
|||
type: "session.next.text.ended",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
text: Schema.String,
|
||||
},
|
||||
})
|
||||
|
|
@ -115,8 +113,7 @@ export namespace Reasoning {
|
|||
type: "session.next.reasoning.started",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
reasoningID: Schema.String,
|
||||
},
|
||||
})
|
||||
|
|
@ -126,8 +123,7 @@ export namespace Reasoning {
|
|||
type: "session.next.reasoning.delta",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
reasoningID: Schema.String,
|
||||
delta: Schema.String,
|
||||
},
|
||||
|
|
@ -138,8 +134,7 @@ export namespace Reasoning {
|
|||
type: "session.next.reasoning.ended",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
reasoningID: Schema.String,
|
||||
text: Schema.String,
|
||||
},
|
||||
|
|
@ -153,8 +148,7 @@ export namespace Tool {
|
|||
type: "session.next.tool.input.started",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
name: Schema.String,
|
||||
},
|
||||
|
|
@ -165,8 +159,7 @@ export namespace Tool {
|
|||
type: "session.next.tool.input.delta",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
delta: Schema.String,
|
||||
},
|
||||
|
|
@ -177,8 +170,7 @@ export namespace Tool {
|
|||
type: "session.next.tool.input.ended",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
text: Schema.String,
|
||||
},
|
||||
|
|
@ -190,8 +182,7 @@ export namespace Tool {
|
|||
type: "session.next.tool.called",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
tool: Schema.String,
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
|
|
@ -203,16 +194,26 @@ export namespace Tool {
|
|||
})
|
||||
export type Called = Schema.Schema.Type<typeof Called>
|
||||
|
||||
export const Progress = Event.define({
|
||||
type: "session.next.tool.progress",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
details: Schema.Record(Schema.String, Schema.Unknown),
|
||||
},
|
||||
})
|
||||
export type Progress = Schema.Schema.Type<typeof Progress>
|
||||
|
||||
export const Success = Event.define({
|
||||
type: "session.next.tool.success",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
title: Schema.String,
|
||||
output: Schema.String.pipe(Schema.optional),
|
||||
attachments: Schema.Array(FileAttachment).pipe(Schema.optional),
|
||||
details: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
provider: Schema.Struct({
|
||||
executed: Schema.Boolean,
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
|
|
@ -225,8 +226,7 @@ export namespace Tool {
|
|||
type: "session.next.tool.error",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
callID: Schema.String,
|
||||
error: Schema.String,
|
||||
provider: Schema.Struct({
|
||||
|
|
@ -254,8 +254,7 @@ export const Retried = Event.define({
|
|||
type: "session.next.retried",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
attempt: Schema.Number,
|
||||
error: RetryError,
|
||||
},
|
||||
|
|
@ -266,8 +265,7 @@ export const Compacted = Event.define({
|
|||
type: "session.next.compacted",
|
||||
aggregate: "sessionID",
|
||||
schema: {
|
||||
timestamp: Schema.DateTimeUtcFromMillis,
|
||||
sessionID: SessionID,
|
||||
...Base,
|
||||
auto: Schema.Boolean,
|
||||
overflow: Schema.Boolean.pipe(Schema.optional),
|
||||
},
|
||||
|
|
@ -287,6 +285,7 @@ export const All = Schema.Union(
|
|||
Tool.Input.Delta,
|
||||
Tool.Input.Ended,
|
||||
Tool.Called,
|
||||
Tool.Progress,
|
||||
Tool.Success,
|
||||
Tool.Error,
|
||||
Reasoning.Started,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue