@jc_stack/ez-agents 0.1.0-beta.25 → 0.1.0-beta.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/docs/releasing.md +3 -2
- package/package.json +1 -1
- package/src/index.ts +4 -2
- package/test/scheduler-relay.test.ts +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-beta.26
|
|
4
|
+
|
|
5
|
+
- Start local software-maintenance wakeups in independent ephemeral sessions,
|
|
6
|
+
including after a relay restart, without trying to resume or persist a
|
|
7
|
+
normal owner conversation. This prevents successful upgrades from producing
|
|
8
|
+
false "failed to start" notifications across direct relays.
|
|
9
|
+
|
|
3
10
|
## 0.1.0-beta.25
|
|
4
11
|
|
|
5
12
|
- Enable Codex Luna `max` reasoning for durable work, schedules and deferred
|
package/docs/releasing.md
CHANGED
|
@@ -17,8 +17,9 @@ separate release bot is not required.
|
|
|
17
17
|
3. Build both Docker targets from a clean checkout:
|
|
18
18
|
`docker build --target test -t ez-release-tests .` and
|
|
19
19
|
`docker build --target runtime -t ez-release-runtime .`.
|
|
20
|
-
Main: `EZ_RELAY_IMAGE=ez-release-runtime node docker/smoke.mjs`.
|
|
21
|
-
WhatsApp
|
|
20
|
+
Main relay: `EZ_RELAY_IMAGE=ez-release-runtime node docker/smoke.mjs`.
|
|
21
|
+
The WhatsApp Compose overlay has no separate relay image; verify its
|
|
22
|
+
provider integration with the synthetic plugin smoke in `docs/plugins.md`.
|
|
22
23
|
4. Create an artifact with `npm pack --ignore-scripts`. Inspect its file list,
|
|
23
24
|
hash it, extract into a fresh directory, copy `docker/pnpm-lock.yaml` to
|
|
24
25
|
`pnpm-lock.yaml`, and run `pnpm install --frozen-lockfile`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jc_stack/ez-agents",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.26",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "A lightweight foundation for persistent business AI assistants using existing AI harnesses, workspaces and plugins.",
|
package/src/index.ts
CHANGED
|
@@ -193,7 +193,9 @@ export const createRelay = (config: Config, launch = startExecutorJob) => {
|
|
|
193
193
|
const launchStarted = performance.now()
|
|
194
194
|
const started = await runs.patch(run.id, { status: 'running', startedAt: new Date().toISOString() })
|
|
195
195
|
if (!started.execution && !run.taskId) throw new Error('Legacy queued work has no pinned AI. Resend the request after /new.')
|
|
196
|
-
const
|
|
196
|
+
const maintenanceWakeup = run.id.startsWith('r_update_')
|
|
197
|
+
const startsOwnSession = Boolean(run.external || run.taskId || run.scheduled || run.replyOnly || maintenanceWakeup)
|
|
198
|
+
const session = startsOwnSession
|
|
197
199
|
? { sessionId: randomUUID(), hasStarted: false, nativeSessionId: undefined }
|
|
198
200
|
: await control.executionSession(started.execution!)
|
|
199
201
|
const selected = run.taskId ? chatPreset('codex') : started.execution!.preset
|
|
@@ -211,7 +213,7 @@ export const createRelay = (config: Config, launch = startExecutorJob) => {
|
|
|
211
213
|
sessionId: session.nativeSessionId || session.sessionId,
|
|
212
214
|
isResume: session.hasStarted,
|
|
213
215
|
eventSource: run.external?.sourceId,
|
|
214
|
-
onSession: run.external || run.taskId || run.replyOnly ? undefined : async (id) => { await runs.patch(run.id,{nativeSessionId:id}); if (!run.scheduled) await control.saveNativeSession(session.sessionId,id) },
|
|
216
|
+
onSession: run.external || run.taskId || run.replyOnly || maintenanceWakeup ? undefined : async (id) => { await runs.patch(run.id,{nativeSessionId:id}); if (!run.scheduled) await control.saveNativeSession(session.sessionId,id) },
|
|
215
217
|
})
|
|
216
218
|
const executionStarted = performance.now()
|
|
217
219
|
// Attach before disk writes: a fast child can close while PID persistence
|
|
@@ -11,8 +11,33 @@ import { ControlStore } from '../src/control-state.js'
|
|
|
11
11
|
import { RunStore } from '../src/runs.js'
|
|
12
12
|
import { Scheduler } from '../src/scheduler.js'
|
|
13
13
|
import { initialPreset } from '../src/ai.js'
|
|
14
|
+
import { randomUUID } from 'node:crypto'
|
|
14
15
|
|
|
15
16
|
const until=async(check:()=>Promise<boolean>)=>{for(let i=0;i<200;i++){if(await check())return;await new Promise(r=>setTimeout(r,20))}throw new Error('Timed out')}
|
|
17
|
+
|
|
18
|
+
test('maintenance wakeups use an independent ephemeral session after a relay restart',async()=>{
|
|
19
|
+
const dir=await mkdtemp(join(tmpdir(),'ez-maintenance-session-')),control=new ControlStore(dir,1000),runs=new RunStore(dir)
|
|
20
|
+
let launchSession='',onSessionCalls=0
|
|
21
|
+
const relay=createRelay({workspace:dir,controlDir:dir,pairingTtlMs:1000,executorTimeoutMs:0,executorCli:'codex',telegramBotToken:'fixture'},async(_texts,options)=>{
|
|
22
|
+
launchSession=options.sessionId ?? ''
|
|
23
|
+
if(options.onSession){onSessionCalls++;await options.onSession('native-maintenance')}
|
|
24
|
+
const child=spawn(process.execPath,['-e','setTimeout(()=>{},10)'],{detached:process.platform!=='win32'})
|
|
25
|
+
await once(child,'spawn')
|
|
26
|
+
return {child,cleanup:async()=>{},stdout:''}
|
|
27
|
+
})
|
|
28
|
+
relay.bot.botInfo={id:999,is_bot:true,first_name:'Fixture',username:'fixture_bot'} as typeof relay.bot.botInfo
|
|
29
|
+
relay.bot.api.config.use(async()=>({ok:true,result:{message_id:42}}) as never)
|
|
30
|
+
try{
|
|
31
|
+
await control.requestPairing(101,101);await control.approveOwner(101)
|
|
32
|
+
const execution={sessionId:randomUUID(),preset:initialPreset('codex')}
|
|
33
|
+
await runs.create({id:'r_update_fixture',chatId:101,telegramUserId:101,texts:['maintenance'],execution})
|
|
34
|
+
await relay.drainSources()
|
|
35
|
+
await until(async()=> (await runs.get('r_update_fixture'))?.status==='completed')
|
|
36
|
+
assert.notEqual(launchSession,execution.sessionId)
|
|
37
|
+
assert.equal(onSessionCalls,0)
|
|
38
|
+
}finally{await relay.stop();await rm(dir,{recursive:true,force:true})}
|
|
39
|
+
})
|
|
40
|
+
|
|
16
41
|
test('chat replies through the real ingress/outbox while scheduled CLI remains alive; targeted cancellation',async()=>{
|
|
17
42
|
const dir=await mkdtemp(join(tmpdir(),'ez-scheduler-relay-')), children:ReturnType<typeof spawn>[]=[]
|
|
18
43
|
const runs=new RunStore(dir),scheduler=new Scheduler(dir),control=new ControlStore(dir,1000)
|