feat: remove "插话" badge displayed in user message

This commit is contained in:
07akioni
2026-07-31 19:12:16 +08:00
parent 7239a2201e
commit f9dc4aa702
28 changed files with 191 additions and 129 deletions
@@ -40,9 +40,9 @@ function effectAt<T extends InputEffect['type']>(
}
/** Drive plain → adjudicating and hand back the minted attempt. */
function enterAdjudicating(m: InputMachine, draft: string, mode: 'queue' | 'steer' = 'queue'): SubmitAttempt {
function enterAdjudicating(m: InputMachine, draft: string): SubmitAttempt {
m.dispatch({ type: 'draft-changed', draft })
const fx = m.dispatch({ type: 'enter', mode })
const fx = m.dispatch({ type: 'enter' })
return effectAt(fx, 0, 'adjudicate').attempt
}
@@ -52,7 +52,7 @@ function enterSubmitting(m: InputMachine, name: string, args: string): { attempt
m.dispatch({ type: 'draft-changed', draft: `/${name.slice(0, 2)}` })
m.dispatch({ type: 'begin-command', claim, span: spanOf(m, 0, m.state.draft.length) })
m.dispatch({ type: 'draft-changed', draft: claim.token + args })
const fx = m.dispatch({ type: 'enter', mode: 'queue' })
const fx = m.dispatch({ type: 'enter' })
return { attempt: effectAt(fx, 0, 'begin-submit').attempt, claim }
}
@@ -63,24 +63,24 @@ function staleAttempt(): SubmitAttempt {
describe('input-machine: plain × enter', () => {
it('empty and whitespace-only drafts produce nothing', () => {
const m = new InputMachine()
expect(m.dispatch({ type: 'enter', mode: 'queue' })).toEqual([])
expect(m.dispatch({ type: 'enter' })).toEqual([])
m.dispatch({ type: 'draft-changed', draft: ' \n ' })
expect(m.dispatch({ type: 'enter', mode: 'queue' })).toEqual([])
expect(m.dispatch({ type: 'enter' })).toEqual([])
expect(m.state.phase).toBe('plain')
})
it('non-command text falls to the default sink with the given mode', () => {
it('non-command text falls to the default sink', () => {
const m = new InputMachine()
m.dispatch({ type: 'draft-changed', draft: 'hello world' })
expect(m.dispatch({ type: 'enter', mode: 'steer' }))
.toEqual([{ type: 'default-sink', draft: 'hello world', mode: 'steer' }])
expect(m.dispatch({ type: 'enter' }))
.toEqual([{ type: 'default-sink', draft: 'hello world' }])
expect(m.state.phase).toBe('plain')
})
it('leading "/" enters adjudicating with a minted attempt carrying the draft snapshot', () => {
const m = new InputMachine()
m.dispatch({ type: 'draft-changed', draft: '/goal x' })
const fx = m.dispatch({ type: 'enter', mode: 'queue' })
const fx = m.dispatch({ type: 'enter' })
const eff = effectAt(fx, 0, 'adjudicate')
expect(eff.draft).toBe('/goal x')
expect(eff.attempt.draftSnapshot).toBe('/goal x')
@@ -91,14 +91,14 @@ describe('input-machine: plain × enter', () => {
it('leading is judged after trim including newlines', () => {
const m = new InputMachine()
m.dispatch({ type: 'draft-changed', draft: '\n\n/goal x' })
expect(m.dispatch({ type: 'enter', mode: 'queue' })[0]?.type).toBe('adjudicate')
expect(m.dispatch({ type: 'enter' })[0]?.type).toBe('adjudicate')
})
it('a non-whitespace prefix before "/" is not leading — default sink', () => {
const m = new InputMachine()
m.dispatch({ type: 'draft-changed', draft: '第一行\n/goal x' })
expect(m.dispatch({ type: 'enter', mode: 'queue' }))
.toEqual([{ type: 'default-sink', draft: '第一行\n/goal x', mode: 'queue' }])
expect(m.dispatch({ type: 'enter' }))
.toEqual([{ type: 'default-sink', draft: '第一行\n/goal x' }])
})
})
@@ -124,11 +124,11 @@ describe('input-machine: adjudication outcomes', () => {
expect(effectAt(b.dispatch({ type: 'adjudicated', attempt: attemptB, outcome: { claim: claimOf('goal') } }), 0, 'begin-submit').args).toBe('x')
})
it('undefined outcome falls back to the default sink preserving the enter mode', () => {
it('undefined outcome falls back to the default sink', () => {
const m = new InputMachine()
const attempt = enterAdjudicating(m, '/unknown thing', 'steer')
const attempt = enterAdjudicating(m, '/unknown thing')
expect(m.dispatch({ type: 'adjudicated', attempt, outcome: undefined }))
.toEqual([{ type: 'default-sink', draft: '/unknown thing', mode: 'steer' }])
.toEqual([{ type: 'default-sink', draft: '/unknown thing' }])
expect(m.state.phase).toBe('plain')
})
@@ -152,7 +152,7 @@ describe('input-machine: adjudication outcomes', () => {
it('enter is a no-op while adjudicating (pending lock)', () => {
const m = new InputMachine()
enterAdjudicating(m, '/goal x')
expect(m.dispatch({ type: 'enter', mode: 'queue' })).toEqual([])
expect(m.dispatch({ type: 'enter' })).toEqual([])
expect(m.state.phase).toBe('adjudicating')
})
@@ -587,7 +587,7 @@ describe('input-machine: paste plane', () => {
const b = new InputMachine()
b.dispatch({ type: 'paste-begin', text: 'plain text', selection: { start: 0, end: 0 } })
b.dispatch({ type: 'enter', mode: 'queue' })
b.dispatch({ type: 'enter' })
expect(b.state.paste).toBeUndefined()
})
@@ -755,7 +755,7 @@ describe('input-machine: submitting transaction', () => {
it('enter and begin-command are locked; draft-changed is recorded without leaving submitting', () => {
const m = new InputMachine()
enterSubmitting(m, 'goal', 'x')
expect(m.dispatch({ type: 'enter', mode: 'queue' })).toEqual([])
expect(m.dispatch({ type: 'enter' })).toEqual([])
expect(m.dispatch({ type: 'draft-changed', draft: '/goal y' })).toEqual([])
expect(m.state).toMatchObject({ phase: 'submitting', draft: '/goal y' })
})
@@ -768,7 +768,7 @@ describe('input-machine: submitting transaction', () => {
m.dispatch({ type: 'draft-changed', draft: '/go', editRange: { start: 0, end: 1, insertedLength: 0 } })
m.dispatch({ type: 'begin-command', claim: claimOf('goal'), span: spanOf(m, 0, 3) })
m.dispatch({ type: 'draft-changed', draft: '/goal go' })
const attempt = effectAt(m.dispatch({ type: 'enter', mode: 'queue' }), 0, 'begin-submit').attempt
const attempt = effectAt(m.dispatch({ type: 'enter' }), 0, 'begin-submit').attempt
const fx = m.dispatch({ type: 'submit-settled', attempt, ok: true, outcome: { kind: 'success', text: 'goal set' } })
expect(fx).toEqual([{ type: 'notice', level: 'info', text: 'goal set' }])
expect(m.state).toMatchObject({ phase: 'plain', draft: '', occurrences: [] })
@@ -809,7 +809,7 @@ describe('input-machine: submitting transaction', () => {
const m = new InputMachine()
const { attempt: first } = enterSubmitting(m, 'goal', 'x')
m.dispatch({ type: 'submit-settled', attempt: first, ok: false, message: 'retry' })
const second = effectAt(m.dispatch({ type: 'enter', mode: 'queue' }), 0, 'begin-submit').attempt
const second = effectAt(m.dispatch({ type: 'enter' }), 0, 'begin-submit').attempt
expect(second.seq).not.toBe(first.seq)
expect(m.dispatch({ type: 'submit-settled', attempt: first, ok: true })).toEqual([])
expect(m.state.phase).toBe('submitting')