Merge remote-tracking branch 'origin/master' into codex/simp-prune-tools-prompt-surface

# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/session/README.md
#	packages/core/session/tests/derived-cache.spec.ts
This commit is contained in:
Tianyi Cui
2026-07-14 17:30:34 +08:00
562 changed files with 4438 additions and 12565 deletions

View File

@@ -682,16 +682,9 @@ describe('ToolRegistry', () => {
})
it('register() returns the EXACT effect disposer: a composite yield nests the teardown in order', async () => {
// The registry-disposer convention (set by agents.register): the returned
// function IS the cordis effect disposer, so a composite (generator)
// effect that yields it has the unregistration run at that yield's LIFO
// position on owner unload. A wrapper would leave the inner effect
// disposing as a CONCURRENT SIBLING of the composite; the async probe
// below (disposed first, LIFO) yields the event loop exactly like the
// agent factory's stop-and-drain link, and a sibling unregistration fires
// in that window — the probe would observe the tool already gone. Pins
// the convention for the whole register-method family (system-prompt
// registrars, registerProvider, setFactory share the same return).
// Registry methods return the exact Cordis effect disposer so a composite yield places
// unregistration at its LIFO position. A wrapper would create a concurrent sibling; this async
// probe yields during earlier teardown and would then observe the tool already removed.
const ctx = await setup()
const order: string[] = []
const fiber = await ctx.plugin(Object.assign((inner: Context) => {
@@ -978,20 +971,18 @@ describe('schema DSL edge cases', () => {
port: { type: 'number' },
},
})
// no 'required' key in the nested object because nothing is required
const config = jsonSchema.properties['config'] as Record<string, unknown>
expect('required' in config).toBe(false)
})
})
describe('schema DSL regressions (Codex review round 2)', () => {
describe('schema DSL optional and nested contracts', () => {
it('InferArgs makes non-required keys genuinely optional (omittable)', () => {
type Args = InferArgs<{
path: { type: 'string'; required: true }
limit: { type: 'number' }
}>
expectTypeOf<Args>().toEqualTypeOf<{ path: string; limit?: number }>()
// omitting the optional key is assignable — the actual regression
const omitted: Args = { path: '/tmp' }
expect(omitted.limit).toBeUndefined()
})