fix(core): reject unknown session interrupts
This commit is contained in:
parent
eec6cd5234
commit
fb8d775fec
3 changed files with 35 additions and 13 deletions
|
|
@ -276,7 +276,7 @@ export interface Interface {
|
||||||
readonly active: Effect.Effect<ReadonlySet<SessionSchema.ID>>
|
readonly active: Effect.Effect<ReadonlySet<SessionSchema.ID>>
|
||||||
readonly background: (sessionID: SessionSchema.ID) => Effect.Effect<void, NotFoundError>
|
readonly background: (sessionID: SessionSchema.ID) => Effect.Effect<void, NotFoundError>
|
||||||
readonly resume: (sessionID: SessionSchema.ID) => Effect.Effect<void, NotFoundError | SessionRunner.RunError>
|
readonly resume: (sessionID: SessionSchema.ID) => Effect.Effect<void, NotFoundError | SessionRunner.RunError>
|
||||||
readonly interrupt: (sessionID: SessionSchema.ID) => Effect.Effect<void>
|
readonly interrupt: (sessionID: SessionSchema.ID) => Effect.Effect<void, NotFoundError>
|
||||||
readonly synthetic: (input: {
|
readonly synthetic: (input: {
|
||||||
id?: SessionMessage.ID
|
id?: SessionMessage.ID
|
||||||
sessionID: SessionSchema.ID
|
sessionID: SessionSchema.ID
|
||||||
|
|
@ -804,7 +804,12 @@ const layer = Layer.effect(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
interrupt: Effect.fn("V2Session.interrupt")((sessionID) =>
|
interrupt: Effect.fn("V2Session.interrupt")((sessionID) =>
|
||||||
Effect.uninterruptible(execution.interrupt(sessionID)),
|
Effect.uninterruptible(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* result.get(sessionID)
|
||||||
|
yield* execution.interrupt(sessionID)
|
||||||
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
revert: {
|
revert: {
|
||||||
stage: Effect.fn("V2Session.revert.stage")(function* (input) {
|
stage: Effect.fn("V2Session.revert.stage")(function* (input) {
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,13 @@ export const Plugin = {
|
||||||
yield* runtime.session.prompt({ sessionID: child.id, text: input.prompt, resume: false })
|
yield* runtime.session.prompt({ sessionID: child.id, text: input.prompt, resume: false })
|
||||||
yield* runtime.session.resume(child.id)
|
yield* runtime.session.resume(child.id)
|
||||||
return yield* latestAssistantText(child.id)
|
return yield* latestAssistantText(child.id)
|
||||||
}).pipe(Effect.onInterrupt(() => runtime.session.interrupt(child.id)))
|
}).pipe(
|
||||||
|
Effect.onInterrupt(() =>
|
||||||
|
runtime.session
|
||||||
|
.interrupt(child.id)
|
||||||
|
.pipe(Effect.catchTag("Session.NotFoundError", () => Effect.void)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const info = yield* runtime.job.start({
|
const info = yield* runtime.job.start({
|
||||||
id: child.id,
|
id: child.id,
|
||||||
|
|
@ -208,13 +214,21 @@ export const Plugin = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = yield* runtime.job.block({ id: child.id, sessionID: context.sessionID }).pipe(
|
const result = yield* runtime.job
|
||||||
Effect.onInterrupt(() =>
|
.block({ id: child.id, sessionID: context.sessionID })
|
||||||
Effect.all([runtime.session.interrupt(child.id), runtime.job.cancel(child.id)], {
|
.pipe(
|
||||||
discard: true,
|
Effect.onInterrupt(() =>
|
||||||
}),
|
Effect.all(
|
||||||
),
|
[
|
||||||
)
|
runtime.session
|
||||||
|
.interrupt(child.id)
|
||||||
|
.pipe(Effect.catchTag("Session.NotFoundError", () => Effect.void)),
|
||||||
|
runtime.job.cancel(child.id),
|
||||||
|
],
|
||||||
|
{ discard: true },
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
if (result?.type === "backgrounded") {
|
if (result?.type === "backgrounded") {
|
||||||
yield* notifyWhenDone(context.sessionID, child.id, agent.name, input.description)
|
yield* notifyWhenDone(context.sessionID, child.id, agent.name, input.description)
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -156,13 +156,16 @@ describe("SessionV2.prompt", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("delegates interruption without requiring a recorded Session", () =>
|
it.effect("rejects interruption for an unknown Session", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const session = yield* SessionV2.Service
|
const session = yield* SessionV2.Service
|
||||||
interruptCalls.length = 0
|
interruptCalls.length = 0
|
||||||
|
const missing = SessionV2.ID.make("ses_missing")
|
||||||
|
|
||||||
yield* session.interrupt(SessionV2.ID.make("ses_missing"))
|
expect(yield* session.interrupt(missing).pipe(Effect.flip)).toEqual(
|
||||||
expect(interruptCalls).toEqual([SessionV2.ID.make("ses_missing")])
|
new SessionV2.NotFoundError({ sessionID: missing }),
|
||||||
|
)
|
||||||
|
expect(interruptCalls).toEqual([])
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue