Skip to content

Commit e00f492

Browse files
authored
Merge pull request #225 from aictrl-dev/refactor/issue-223-interactive
refactor(session): remove interactive user-message machinery (Part of #223)
2 parents 6eee886 + 2164022 commit e00f492

7 files changed

Lines changed: 276 additions & 508 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
- **Messages written in the same millisecond keep their order** — Reading a session's messages now breaks `time_created` ties by message ID. Before, messages written in the same millisecond came back oldest first. A compaction writes its request, its summary and the continue message in quick succession, so the prompt loop could miss the finished summary and compact again, sending an extra model request. (#200)
1212
- **Retry waits are bounded for every status** — No single wait between retries exceeds 5 minutes. A retryable error of any status whose `Retry-After` / `retry-after-ms` asks for longer is no longer retried: a 429 still fails as `usage_limit` (#174), and any other status (for example a 503 or 529 asking for `retry-after: 18000`, which used to sleep about 5 hours per attempt) fails at once with the provider error, `session_error.reason` from its status (`provider` for a 5xx) and exit 1, with no `retry` event. Exponential backoff without a retry hint now stops at 30 s even when the response has headers, as every AI SDK HTTP error does, so a hintless 429 or 5xx retries for about 3.5 minutes in all instead of about 34. A zero or negative `Retry-After` now counts as no hint and backs off, instead of retrying with no wait. With 10 retries the waits total at most 50 minutes. (closes #175)
1313

14+
### Internal
15+
16+
- **A session runs one prompt at a time** — The prompt loop no longer queues a second prompt for a session that is already running one. The second prompt now fails with `Session <id> is busy: it already has a running prompt` before it writes a user message. A headless run has one user turn, so the only reachable case is two parallel `task` calls that resume the same `task_id`: the second call now returns that error to the model instead of waiting. The unused `!` shell command path (`SessionPrompt.shell`) and `Session.initialize` are removed. (Part of #223)
17+
1418
### Security
1519

1620
- **drizzle-orm 1.0.0-beta.20** — `drizzle-orm` and `drizzle-kit` move from `1.0.0-beta.12-a5629fb` to `1.0.0-beta.20`, the first release patched for GHSA-gpj5-g38j-94v9 (SQL injection through improperly escaped SQL identifiers; the CLI never passed untrusted identifiers to drizzle). Existing databases open as before: on first start drizzle adds `name` and `applied_at` columns to `__drizzle_migrations` and fills in the names of the migrations already applied, without running them again. The upgraded database still opens with 0.5.1. (closes #61)

‎packages/cli/src/cli/cmd/run.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,10 +1104,10 @@ export const RunCommand = cmd({
11041104
}
11051105

11061106
// Race loopDone against promptResult to handle early prompt failures.
1107-
// If SessionPrompt.prompt() rejects BEFORE it enters its internal loop()
1108-
// (e.g., Session.get() fails, model not found), no session.status idle event
1109-
// is emitted, so loopDone would hang forever. Racing ensures we surface
1110-
// the error and exit.
1107+
// If SessionPrompt.prompt() rejects before it starts its model loop
1108+
// (e.g., Session.get() fails, model not found, Session.BusyError), no
1109+
// session.status idle event is emitted, so loopDone would hang forever.
1110+
// Racing ensures we surface the error and exit.
11111111
const result = await Promise.race([
11121112
loopDone,
11131113
promptResult.then(

‎packages/cli/src/session/index.ts‎

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ import { ProjectTable } from "../project/project.sql"
1616
import { Log } from "../util/log"
1717
import { MessageV2 } from "./message-v2"
1818
import { Instance } from "../project/instance"
19-
import { SessionPrompt } from "./prompt"
2019
import { fn } from "@/util/fn"
21-
import { Command } from "../command"
2220

2321
import type { Provider } from "@/provider/provider"
2422
import { PermissionNext } from "@/permission/next"
@@ -741,25 +739,7 @@ export namespace Session {
741739

742740
export class BusyError extends Error {
743741
constructor(public readonly sessionID: string) {
744-
super(`Session ${sessionID} is busy`)
742+
super(`Session ${sessionID} is busy: it already has a running prompt`)
745743
}
746744
}
747-
748-
export const initialize = fn(
749-
z.object({
750-
sessionID: Identifier.schema("session"),
751-
modelID: z.string(),
752-
providerID: z.string(),
753-
messageID: Identifier.schema("message"),
754-
}),
755-
async (input) => {
756-
await SessionPrompt.command({
757-
sessionID: input.sessionID,
758-
messageID: input.messageID,
759-
model: input.providerID + "/" + input.modelID,
760-
command: Command.Default.INIT,
761-
arguments: "",
762-
})
763-
},
764-
)
765745
}

0 commit comments

Comments
 (0)