Ship Assistent 0.14.0: chat sessions, ask-only hops, and context compression.
Per-chat Generate session with sparse deltas; drop Cards/Civitai/wanted hops; rolling history summary via the same Ollama model with a budget chip and /compress. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+54
-14
@@ -3,35 +3,75 @@ import assert from 'node:assert/strict';
|
||||
import {
|
||||
extractPatch,
|
||||
isPatchObject,
|
||||
isCardObject,
|
||||
normalizePatch,
|
||||
setPatchKeys,
|
||||
} from '../src/patch.js';
|
||||
import {
|
||||
mergeDelta,
|
||||
emptySession,
|
||||
patchWantsGenerate,
|
||||
sessionFromLegacyParams,
|
||||
toPersistParams,
|
||||
resolveTurnIntent,
|
||||
} from '../src/session.js';
|
||||
|
||||
describe('patch.js', () => {
|
||||
it('extractPatch finds generation patch in fence', () => {
|
||||
const text = 'Here you go\n```json\n{"prompt":"A red fox in snow","actions":["generate"]}\n```';
|
||||
const text = 'Here you go\n```json\n{"prompt":"A red fox in snow","generate":true}\n```';
|
||||
const { prose, patch } = extractPatch(text);
|
||||
assert.ok(patch);
|
||||
assert.equal(patch.prompt, 'A red fox in snow');
|
||||
assert.equal(patch.generate, true);
|
||||
assert.ok(!prose.includes('```'));
|
||||
});
|
||||
|
||||
it('isCardObject vs isPatchObject', () => {
|
||||
const card = { kind: 'lora', name: 'Foo', triggers: ['bar'] };
|
||||
const gen = { prompt: 'test', actions: ['generate'] };
|
||||
assert.equal(isCardObject(card), true);
|
||||
assert.equal(isPatchObject(card), false);
|
||||
assert.equal(isPatchObject(gen), true);
|
||||
});
|
||||
|
||||
it('normalizePatch aliases civitai_query', () => {
|
||||
const p = normalizePatch({ civitai_query: 'anime style' });
|
||||
assert.equal(p.search_query, 'anime style');
|
||||
it('normalizePatch maps legacy actions generate', () => {
|
||||
const p = normalizePatch({ prompt: 'x', actions: ['generate'] });
|
||||
assert.equal(p.generate, true);
|
||||
});
|
||||
|
||||
it('scheduler-only patch is detected with full key list', () => {
|
||||
setPatchKeys(['prompt', 'scheduler']);
|
||||
setPatchKeys(['prompt', 'scheduler', 'generate', 'ask']);
|
||||
assert.equal(isPatchObject({ scheduler: 'euler' }), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('session.js', () => {
|
||||
it('mergeDelta is sparse and keeps other fields', () => {
|
||||
let s = emptySession();
|
||||
s.gen.prompt = 'old';
|
||||
s.gen.steps = 8;
|
||||
s = mergeDelta(s, { aspect: '16:9', generate: true });
|
||||
assert.equal(s.gen.prompt, 'old');
|
||||
assert.equal(s.gen.steps, 8);
|
||||
assert.equal(s.gen.aspect, '16:9');
|
||||
assert.equal(patchWantsGenerate({ generate: true }), true);
|
||||
assert.equal(patchWantsGenerate({ actions: ['generate'] }), true);
|
||||
});
|
||||
|
||||
it('legacy flat params upgrade to session shape', () => {
|
||||
const s = sessionFromLegacyParams({
|
||||
prompt: 'fox',
|
||||
steps: 28,
|
||||
loras: [{ name: 'a', weight: 0.8 }],
|
||||
genResults: [{ id: 'var1', src: '/View/x.png' }],
|
||||
persona: 'leonid',
|
||||
});
|
||||
assert.equal(s.gen.prompt, 'fox');
|
||||
assert.equal(s.gen.steps, 28);
|
||||
assert.equal(s.board.genResults.length, 1);
|
||||
const blob = toPersistParams(s);
|
||||
assert.ok(blob.gen);
|
||||
assert.ok(blob.board);
|
||||
});
|
||||
|
||||
it('resolveTurnIntent vetoes generate', () => {
|
||||
const intent = resolveTurnIntent(
|
||||
{ generate: true, prompt: 'x' },
|
||||
'не генерируй',
|
||||
{ vetoFn: (t) => /не\s+генерир/i.test(t) },
|
||||
);
|
||||
assert.equal(intent.generate, false);
|
||||
assert.equal(intent.vetoed, true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user