From 2e7946dd0bd87b38bf72f37691ba4f5c3c0c49f4 Mon Sep 17 00:00:00 2001 From: Sairaalasanasto Dev Date: Sat, 12 Sep 2026 00:56:47 +0300 Subject: [PATCH 1/2] fix(conversation): always send type and extra in create body aioncore v0.1.72 rejects POST /api/conversations bodies that lack the top-level type or extra field with 'Invalid JSON request body'. The body builder dropped type whenever an assistant was selected and dropped an empty extra, so every first submit from the home screen failed with 400. Always pass type through, default extra to {}, and set the engine type ('aionrs' | 'acp') at both useGuidSend call sites. --- packages/desktop/src/common/adapter/apiModelMapper.ts | 7 ++++--- .../desktop/src/renderer/pages/guid/hooks/useGuidSend.ts | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/desktop/src/common/adapter/apiModelMapper.ts b/packages/desktop/src/common/adapter/apiModelMapper.ts index 020864f5e34..0167d70b02b 100644 --- a/packages/desktop/src/common/adapter/apiModelMapper.ts +++ b/packages/desktop/src/common/adapter/apiModelMapper.ts @@ -54,13 +54,14 @@ export type CreateConversationBodyInput = { * agent types carry model info via `extra`. */ export function buildCreateConversationBody(p: CreateConversationBodyInput): Record { - const hasAssistant = p.assistant !== undefined && p.assistant !== null; + // aioncore >= v0.1.72 rejects create bodies without top-level `type` and + // `extra` ("Invalid JSON request body"), so both must always be present. const body: Record = { - type: hasAssistant ? undefined : p.type, + type: p.type, id: p.id, name: p.name, assistant: p.assistant, - extra: p.extra, + extra: p.extra ?? {}, }; const model = p.type === 'acp' ? undefined : toApiModelOptional(p.model); if (model) body.model = model; diff --git a/packages/desktop/src/renderer/pages/guid/hooks/useGuidSend.ts b/packages/desktop/src/renderer/pages/guid/hooks/useGuidSend.ts index 710e988851a..0a26143cb9a 100644 --- a/packages/desktop/src/renderer/pages/guid/hooks/useGuidSend.ts +++ b/packages/desktop/src/renderer/pages/guid/hooks/useGuidSend.ts @@ -177,6 +177,7 @@ export const useGuidSend = (deps: GuidSendDeps): GuidSendResult => { } try { const conversation = await ipcBridge.conversation.create.invoke({ + type: 'aionrs', name: input, model: current_model, assistant: { @@ -232,6 +233,7 @@ export const useGuidSend = (deps: GuidSendDeps): GuidSendResult => { try { const conversation = await ipcBridge.conversation.create.invoke({ + type: 'acp', name: input, assistant: { id: assistantConversationId, From e744cab3263fdbe8102d23ac20a0437a8c071bbf Mon Sep 17 00:00:00 2001 From: Sairaalasanasto Dev Date: Sat, 12 Sep 2026 01:19:59 +0300 Subject: [PATCH 2/2] test(conversation): assert type is sent with assistant creates Update the four assertions that encoded the old contract (type stripped when an assistant identity is present) to expect the engine type ('aionrs' | 'acp') to be passed through, matching the aioncore v0.1.72 requirement fixed in the previous commit. --- tests/unit/common-adapter/apiModelMapper.test.ts | 4 ++-- tests/unit/renderer/useGuidSend.dom.test.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/common-adapter/apiModelMapper.test.ts b/tests/unit/common-adapter/apiModelMapper.test.ts index 2e0d04baafa..563ec7372db 100644 --- a/tests/unit/common-adapter/apiModelMapper.test.ts +++ b/tests/unit/common-adapter/apiModelMapper.test.ts @@ -154,7 +154,7 @@ describe('apiModelMapper', () => { expect('model' in body).toBe(false); }); - it('strips legacy type when assistant identity is present', () => { + it('passes type through when assistant identity is present', () => { const body = buildCreateConversationBody({ type: 'acp', name: 'hello', @@ -162,7 +162,7 @@ describe('apiModelMapper', () => { extra: {}, }); - expect(body.type).toBeUndefined(); + expect(body.type).toBe('acp'); }); it('omits the top-level model for ACP creates that pass an empty placeholder', () => { diff --git a/tests/unit/renderer/useGuidSend.dom.test.ts b/tests/unit/renderer/useGuidSend.dom.test.ts index 8227698a025..db76a917bac 100644 --- a/tests/unit/renderer/useGuidSend.dom.test.ts +++ b/tests/unit/renderer/useGuidSend.dom.test.ts @@ -94,7 +94,7 @@ describe('useGuidSend', () => { expect(createConversationInvokeMock).toHaveBeenCalledTimes(1); const payload = createConversationInvokeMock.mock.calls[0][0]; - expect(payload.type).toBeUndefined(); + expect(payload.type).toBe('acp'); expect('model' in payload).toBe(false); expect(payload.assistant?.conversation_overrides?.permission).toBe('bypassPermissions'); expect(payload.assistant?.conversation_overrides?.model).toBe('claude-opus'); @@ -200,7 +200,7 @@ describe('useGuidSend', () => { }); const payload = createConversationInvokeMock.mock.calls[0][0]; - expect(payload.type).toBeUndefined(); + expect(payload.type).toBe('aionrs'); expect(payload.model).toBe(deps.current_model); expect(payload.assistant?.id).toBe('bare:aionrs'); expect(payload.assistant?.conversation_overrides?.skill_ids).toEqual(['pdf-reader']); @@ -239,7 +239,7 @@ describe('useGuidSend', () => { const payload = createConversationInvokeMock.mock.calls[0][0]; expect(payload.assistant?.id).toBe('bare:claude'); - expect(payload.type).toBeUndefined(); + expect(payload.type).toBe('acp'); expect('model' in payload).toBe(false); expect(payload.extra.preset_assistant_id).toBeUndefined(); expect(payload.extra.backend).toBeUndefined();