@almyty/acp-server 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- export {};
@@ -1,81 +1 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mapStreamEvent, buildPlanFromPipeline, isTerminalEvent, extractFinalOutput } from '../events.js';
3
- describe('mapStreamEvent', () => {
4
- it('maps node.started to tool_call with running status', () => {
5
- const results = mapStreamEvent({ event: 'node.started', data: { nodeId: 'n1', nodeType: 'tool_call', name: 'get_users' } });
6
- expect(results.length).toBeGreaterThan(0);
7
- const tc = results.find(r => r.type === 'tool_call');
8
- expect(tc).toBeDefined();
9
- expect(tc.status).toBe('running');
10
- });
11
- it('maps node.completed to tool_call_update', () => {
12
- const results = mapStreamEvent({ event: 'node.completed', data: { nodeId: 'n1', output: { users: [] } } });
13
- expect(results.length).toBeGreaterThan(0);
14
- const update = results.find(r => r.type === 'tool_call_update');
15
- expect(update).toBeDefined();
16
- expect(update.status).toBe('completed');
17
- });
18
- it('maps node.error to tool_call_update with error', () => {
19
- const results = mapStreamEvent({ event: 'node.error', data: { nodeId: 'n1', error: 'timeout' } });
20
- expect(results.length).toBeGreaterThan(0);
21
- const update = results.find(r => r.type === 'tool_call_update');
22
- expect(update).toBeDefined();
23
- expect(update.status).toBe('error');
24
- });
25
- it('maps text events to agent_message_chunk', () => {
26
- for (const event of ['text', 'message', 'chunk', 'token']) {
27
- const results = mapStreamEvent({ event, data: { text: 'hello' } });
28
- expect(results.length).toBeGreaterThan(0);
29
- expect(results[0].type).toBe('agent_message_chunk');
30
- }
31
- });
32
- it('maps thinking events to agent_thought_chunk', () => {
33
- const results = mapStreamEvent({ event: 'thinking', data: { text: 'hmm' } });
34
- expect(results.length).toBeGreaterThan(0);
35
- expect(results[0].type).toBe('agent_thought_chunk');
36
- });
37
- it('returns empty array for unknown events', () => {
38
- expect(mapStreamEvent({ event: 'unknown_xyz', data: {} })).toHaveLength(0);
39
- });
40
- });
41
- describe('buildPlanFromPipeline', () => {
42
- it('converts pipeline nodes to plan entries (filters input/output)', () => {
43
- const nodes = [
44
- { id: 'n1', type: 'input', data: {} },
45
- { id: 'n2', type: 'llm_call', data: {} },
46
- { id: 'n3', type: 'tool_call', data: { toolName: 'fetch' } },
47
- { id: 'n4', type: 'output', data: {} },
48
- ];
49
- const plan = buildPlanFromPipeline(nodes);
50
- expect(plan.type).toBe('plan');
51
- // input + output filtered out, llm_call + tool_call remain
52
- expect(plan.entries.length).toBe(2);
53
- });
54
- it('returns empty plan for empty pipeline', () => {
55
- const plan = buildPlanFromPipeline([]);
56
- expect(plan.entries).toHaveLength(0);
57
- });
58
- });
59
- describe('isTerminalEvent', () => {
60
- it('recognizes terminal events', () => {
61
- expect(isTerminalEvent({ event: 'execution.completed', data: {} })).toBe(true);
62
- expect(isTerminalEvent({ event: 'execution.error', data: {} })).toBe(true);
63
- expect(isTerminalEvent({ event: 'run.completed', data: {} })).toBe(true);
64
- });
65
- it('rejects non-terminal events', () => {
66
- expect(isTerminalEvent({ event: 'text', data: {} })).toBe(false);
67
- expect(isTerminalEvent({ event: 'node.started', data: {} })).toBe(false);
68
- });
69
- });
70
- describe('extractFinalOutput', () => {
71
- it('extracts text from output', () => {
72
- expect(extractFinalOutput({ event: 'execution.completed', data: { output: 'result' } })).toBe('result');
73
- });
74
- it('stringifies object output', () => {
75
- const result = extractFinalOutput({ event: 'execution.completed', data: { output: { key: 'val' } } });
76
- expect(result).toContain('key');
77
- });
78
- it('returns undefined for missing output', () => {
79
- expect(extractFinalOutput({ event: 'execution.completed', data: {} })).toBeUndefined();
80
- });
81
- });
1
+ "use strict";
package/dist/agent.js CHANGED
@@ -213,7 +213,8 @@ export class AlmytyAcpAgent {
213
213
  throw new JsonRpcError(INVALID_PARAMS, `Session not found: ${sessionId}`);
214
214
  }
215
215
  // Extract text from ContentBlock array
216
- const content = params.content;
216
+ // ACP spec uses "prompt", some clients send "content"
217
+ const content = (params.prompt || params.content);
217
218
  const inputText = extractTextFromContent(content);
218
219
  if (!inputText) {
219
220
  throw new JsonRpcError(INVALID_PARAMS, 'No text content in prompt');
@@ -489,9 +490,24 @@ export class AlmytyAcpAgent {
489
490
  });
490
491
  }
491
492
  sendSessionUpdate(sessionId, update) {
493
+ // Transform internal format to ACP spec format:
494
+ // - "type" -> "sessionUpdate"
495
+ // - text content wrapped in { type: 'text', text }
496
+ const specUpdate = { ...update };
497
+ if ('type' in specUpdate) {
498
+ specUpdate.sessionUpdate = specUpdate.type;
499
+ delete specUpdate.type;
500
+ }
501
+ // Wrap bare text in content object for message/thought chunks
502
+ if (specUpdate.sessionUpdate === 'agent_message_chunk' || specUpdate.sessionUpdate === 'agent_thought_chunk') {
503
+ if ('text' in specUpdate && !('content' in specUpdate)) {
504
+ specUpdate.content = { type: 'text', text: specUpdate.text };
505
+ delete specUpdate.text;
506
+ }
507
+ }
492
508
  this.sendNotification('session/update', {
493
509
  sessionId,
494
- update,
510
+ update: specUpdate,
495
511
  });
496
512
  }
497
513
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almyty/acp-server",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "ACP agent server for almyty — expose any almyty agent via the Agent Client Protocol",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",