Merge origin/master (agent-scope runtime #224, session-query, run-gates CI harness)
Conflict resolution beyond line merges: the ACP bridge's mode/set re-notify moved inside master's new containment finally (a throwing presenter must not desync the picker), and session/new keeps the modes advertisement beside master's plain object return. dsh-mode's boundary flush moved off the session/event feed onto the loop's interception seams (agent/prompt-submit / agent/turn-continuation): master's scoped dispatch made post-commit session observers observe-only — an append from one re-enters the publishing append — while the two waterfalls fire outside any log emit and bracket the same boundaries; mode.spec's boundary helper now dispatches those seams via agentEvents, and the containment tests stub only the mode/set append. Catalogs, doc graphs, and the module graph regenerated.
This commit is contained in:
@@ -54,7 +54,7 @@ async function setup() {
|
||||
* The registration disposer is tracked so {@link unregisterFakeAgents} can drop
|
||||
* it (simulating the owning session disconnecting before a task completes).
|
||||
*/
|
||||
const fakeAgentDisposers = new Map<Context, (() => void)[]>()
|
||||
const fakeAgentDisposers = new Map<Context, (() => Promise<void> | void)[]>()
|
||||
function registerFakeAgent(ctx: Context, sessionId: string, inject: (...args: unknown[]) => void): Agent {
|
||||
// The registry KEY (agent.id) is deliberately DIFFERENT from the session
|
||||
// token (session.header.id) — a config agent has `agentId !== sessionId`. The
|
||||
@@ -72,7 +72,7 @@ function registerFakeAgent(ctx: Context, sessionId: string, inject: (...args: un
|
||||
|
||||
/** Unregister every fake agent in this ctx (simulate the owning session disconnecting). */
|
||||
function unregisterFakeAgents(ctx: Context): void {
|
||||
for (const dispose of fakeAgentDisposers.get(ctx) ?? []) dispose()
|
||||
for (const dispose of fakeAgentDisposers.get(ctx) ?? []) void dispose()
|
||||
fakeAgentDisposers.delete(ctx)
|
||||
}
|
||||
|
||||
@@ -262,7 +262,6 @@ describe('bash tool', () => {
|
||||
[{ command: ' ', description: 'd' }, /invalid command/],
|
||||
[{ command: 'x', description: ' ' }, /invalid description/],
|
||||
[{ command: 'x', description: 'd', timeoutMs: -1 }, /invalid timeoutMs/],
|
||||
[{ command: 'x', description: 'd', timeoutMs: Number.NaN }, /invalid timeoutMs/],
|
||||
])('rejects value-invalid args %j', async (args, pattern) => {
|
||||
const ctx = await setup()
|
||||
const result = await call(ctx, 'bash', args)
|
||||
@@ -270,6 +269,15 @@ describe('bash tool', () => {
|
||||
expect(text(result)).toMatch(pattern)
|
||||
})
|
||||
|
||||
it('rejects a non-JSON numeric argument before tool-specific validation', async () => {
|
||||
const ctx = await setup()
|
||||
const result = await call(ctx, 'bash', {
|
||||
command: 'x', description: 'd', timeoutMs: Number.NaN,
|
||||
})
|
||||
expect(result.isError).toBe(true)
|
||||
expect(text(result)).toContain('tool execution arguments must be losslessly JSON-serializable')
|
||||
})
|
||||
|
||||
it('registers all three schemas in the system prompt assembly', async () => {
|
||||
const ctx = await setup()
|
||||
const names = ctx.tools.schemas().map(schema => schema.name)
|
||||
|
||||
Reference in New Issue
Block a user