@nextclaw/ncp 0.1.1 → 0.3.0

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.
package/README.md CHANGED
@@ -5,7 +5,7 @@ Core protocol types and endpoint abstractions for universal communication in Nex
5
5
  ## Build
6
6
 
7
7
  ```bash
8
- pnpm -C packages/nextclaw-ncp build
8
+ pnpm -C packages/ncp-packages/nextclaw-ncp build
9
9
  ```
10
10
 
11
11
  ## Scope
package/dist/index.d.ts CHANGED
@@ -163,7 +163,7 @@ type NcpEndpointLatency = "realtime" | "seconds" | "minutes" | "hours" | "days";
163
163
  *
164
164
  * Consumers use the manifest for runtime capability discovery —
165
165
  * e.g. whether to show a typing indicator, whether to offer file uploads,
166
- * or whether session resume is available.
166
+ * or whether an existing run can be streamed again.
167
167
  */
168
168
  type NcpEndpointManifest = {
169
169
  /** Category of this endpoint. */
@@ -178,8 +178,8 @@ type NcpEndpointManifest = {
178
178
  supportsAbort: boolean;
179
179
  /** Whether this endpoint can push messages without a prior user request. */
180
180
  supportsProactiveMessages: boolean;
181
- /** Whether a disconnected session can be resumed by the same `sessionId`. */
182
- supportsSessionResume: boolean;
181
+ /** Whether this endpoint can stream the live events of an active session by `sessionId`. */
182
+ supportsLiveSessionStream: boolean;
183
183
  /**
184
184
  * The subset of `NcpMessagePart` types this endpoint can send or receive.
185
185
  * Using the literal union from `NcpMessagePart["type"]` prevents typos
@@ -215,20 +215,6 @@ type NcpError = {
215
215
  /** Original cause — preserved for debugging but not guaranteed serializable. */
216
216
  cause?: unknown;
217
217
  };
218
- /**
219
- * Throwable form of `NcpError` for use in exception-based control flows.
220
- *
221
- * Bridges typed protocol errors with standard JS `Error` hierarchies so that
222
- * `instanceof` checks and stack traces work as expected.
223
- *
224
- * @example
225
- * throw new NcpErrorException("auth-error", "Missing API key");
226
- */
227
- declare class NcpErrorException extends Error {
228
- readonly code: NcpErrorCode;
229
- readonly details?: Record<string, unknown>;
230
- constructor(code: NcpErrorCode, message: string, details?: Record<string, unknown>);
231
- }
232
218
 
233
219
  type NcpSessionStatus = "idle" | "running";
234
220
  type NcpSessionSummary = {
@@ -236,7 +222,7 @@ type NcpSessionSummary = {
236
222
  messageCount: number;
237
223
  updatedAt: string;
238
224
  status?: NcpSessionStatus;
239
- activeRunId?: string;
225
+ metadata?: Record<string, unknown>;
240
226
  };
241
227
  type ListSessionsOptions = {
242
228
  limit?: number;
@@ -295,20 +281,17 @@ type NcpMessageAcceptedPayload = {
295
281
  correlationId?: string;
296
282
  transportId?: string;
297
283
  };
298
- /** Payload for message.abort: identifies which request or run to cancel. */
284
+ /** Payload for message.abort: identifies which session's active execution to cancel. */
299
285
  type NcpMessageAbortPayload = {
286
+ sessionId: string;
300
287
  messageId?: string;
301
- correlationId?: string;
302
- runId?: string;
303
288
  };
304
289
  /**
305
- * Payload for message.resume-request: resume an existing run by its remote id.
306
- * Used when reconnecting to a stream (e.g. after page refresh).
290
+ * Payload for message.stream-request: attach to the live event stream of a session.
291
+ * Used when reconnecting during an active response or attaching another live reader.
307
292
  */
308
- type NcpResumeRequestPayload = {
293
+ type NcpStreamRequestPayload = {
309
294
  sessionId: string;
310
- remoteRunId: string;
311
- fromEventIndex?: number;
312
295
  metadata?: Record<string, unknown>;
313
296
  };
314
297
  /**
@@ -435,100 +418,134 @@ type NcpToolCallResultPayload = {
435
418
  toolCallId: string;
436
419
  content: unknown;
437
420
  };
421
+ declare enum NcpEventType {
422
+ EndpointReady = "endpoint.ready",
423
+ EndpointError = "endpoint.error",
424
+ MessageRequest = "message.request",
425
+ MessageStreamRequest = "message.stream-request",
426
+ MessageSent = "message.sent",
427
+ MessageAccepted = "message.accepted",
428
+ MessageIncoming = "message.incoming",
429
+ MessageCompleted = "message.completed",
430
+ MessageFailed = "message.failed",
431
+ MessageAbort = "message.abort",
432
+ MessageTextStart = "message.text-start",
433
+ MessageTextDelta = "message.text-delta",
434
+ MessageTextEnd = "message.text-end",
435
+ MessageReasoningStart = "message.reasoning-start",
436
+ MessageReasoningDelta = "message.reasoning-delta",
437
+ MessageReasoningEnd = "message.reasoning-end",
438
+ MessageToolCallStart = "message.tool-call-start",
439
+ MessageToolCallArgs = "message.tool-call-args",
440
+ MessageToolCallArgsDelta = "message.tool-call-args-delta",
441
+ MessageToolCallEnd = "message.tool-call-end",
442
+ MessageToolCallResult = "message.tool-call-result",
443
+ MessageRead = "message.read",
444
+ MessageDelivered = "message.delivered",
445
+ MessageRecalled = "message.recalled",
446
+ MessageReaction = "message.reaction",
447
+ RunStarted = "run.started",
448
+ RunFinished = "run.finished",
449
+ RunError = "run.error",
450
+ RunMetadata = "run.metadata",
451
+ TypingStart = "typing.start",
452
+ TypingEnd = "typing.end",
453
+ PresenceUpdated = "presence.updated"
454
+ }
438
455
  type NcpEndpointEvent = {
439
- type: "endpoint.ready";
456
+ type: NcpEventType.EndpointReady;
440
457
  } | {
441
- type: "message.request";
458
+ type: NcpEventType.MessageRequest;
442
459
  payload: NcpRequestEnvelope;
443
460
  } | {
444
- type: "message.resume-request";
445
- payload: NcpResumeRequestPayload;
461
+ type: NcpEventType.MessageStreamRequest;
462
+ payload: NcpStreamRequestPayload;
446
463
  } | {
447
- type: "message.sent";
464
+ type: NcpEventType.MessageSent;
448
465
  payload: NcpMessageSentPayload;
449
466
  } | {
450
- type: "message.accepted";
467
+ type: NcpEventType.MessageAccepted;
451
468
  payload: NcpMessageAcceptedPayload;
452
469
  } | {
453
- type: "message.incoming";
470
+ type: NcpEventType.MessageIncoming;
454
471
  payload: NcpResponseEnvelope;
455
472
  } | {
456
- type: "message.completed";
473
+ type: NcpEventType.MessageCompleted;
457
474
  payload: NcpCompletedEnvelope;
458
475
  } | {
459
- type: "message.failed";
476
+ type: NcpEventType.MessageFailed;
460
477
  payload: NcpFailedEnvelope;
461
478
  } | {
462
- type: "message.abort";
479
+ type: NcpEventType.MessageAbort;
463
480
  payload: NcpMessageAbortPayload;
464
481
  } | {
465
- type: "endpoint.error";
482
+ type: NcpEventType.EndpointError;
466
483
  payload: NcpError;
467
484
  } | {
468
- type: "run.started";
485
+ type: NcpEventType.RunStarted;
469
486
  payload: NcpRunStartedPayload;
470
487
  } | {
471
- type: "run.finished";
488
+ type: NcpEventType.RunFinished;
472
489
  payload: NcpRunFinishedPayload;
473
490
  } | {
474
- type: "run.error";
491
+ type: NcpEventType.RunError;
475
492
  payload: NcpRunErrorPayload;
476
493
  } | {
477
- type: "run.metadata";
494
+ type: NcpEventType.RunMetadata;
478
495
  payload: NcpRunMetadataPayload;
479
496
  } | {
480
- type: "message.text-start";
497
+ type: NcpEventType.MessageTextStart;
481
498
  payload: NcpTextStartPayload;
482
499
  } | {
483
- type: "message.text-delta";
500
+ type: NcpEventType.MessageTextDelta;
484
501
  payload: NcpTextDeltaPayload;
485
502
  } | {
486
- type: "message.text-end";
503
+ type: NcpEventType.MessageTextEnd;
487
504
  payload: NcpTextEndPayload;
488
505
  } | {
489
- type: "message.reasoning-start";
506
+ type: NcpEventType.MessageReasoningStart;
490
507
  payload: NcpReasoningStartPayload;
491
508
  } | {
492
- type: "message.reasoning-delta";
509
+ type: NcpEventType.MessageReasoningDelta;
493
510
  payload: NcpReasoningDeltaPayload;
494
511
  } | {
495
- type: "message.reasoning-end";
512
+ type: NcpEventType.MessageReasoningEnd;
496
513
  payload: NcpReasoningEndPayload;
497
514
  } | {
498
- type: "message.tool-call-start";
515
+ type: NcpEventType.MessageToolCallStart;
499
516
  payload: NcpToolCallStartPayload;
500
517
  } | {
501
- type: "message.tool-call-args";
518
+ type: NcpEventType.MessageToolCallArgs;
502
519
  payload: NcpToolCallArgsPayload;
503
520
  } | {
504
- type: "message.tool-call-args-delta";
521
+ type: NcpEventType.MessageToolCallArgsDelta;
505
522
  payload: NcpToolCallArgsDeltaPayload;
506
523
  } | {
507
- type: "message.tool-call-end";
524
+ type: NcpEventType.MessageToolCallEnd;
508
525
  payload: NcpToolCallEndPayload;
509
526
  } | {
510
- type: "message.tool-call-result";
527
+ type: NcpEventType.MessageToolCallResult;
511
528
  payload: NcpToolCallResultPayload;
512
529
  } | {
513
- type: "typing.start";
530
+ type: NcpEventType.TypingStart;
514
531
  payload: NcpTypingStartPayload;
515
532
  } | {
516
- type: "typing.end";
533
+ type: NcpEventType.TypingEnd;
517
534
  payload: NcpTypingEndPayload;
518
535
  } | {
519
- type: "presence.updated";
536
+ type: NcpEventType.PresenceUpdated;
520
537
  payload: NcpPresenceUpdatedPayload;
521
538
  } | {
522
- type: "message.read";
539
+ type: NcpEventType.MessageRead;
523
540
  payload: NcpMessageReadPayload;
524
541
  } | {
525
- type: "message.delivered";
542
+ type: NcpEventType.MessageDelivered;
526
543
  payload: NcpMessageDeliveredPayload;
527
544
  } | {
528
- type: "message.recalled";
545
+ type: NcpEventType.MessageRecalled;
529
546
  payload: NcpMessageRecalledPayload;
530
547
  } | {
531
- type: "message.reaction";
548
+ type: NcpEventType.MessageReaction;
532
549
  payload: NcpMessageReactionPayload;
533
550
  };
534
551
  type NcpEndpointSubscriber = (event: NcpEndpointEvent) => void;
@@ -568,7 +585,7 @@ type NcpRunFinalMetadata = {
568
585
  * const endpoint: NcpEndpoint = new MyAgentEndpoint(options);
569
586
  * await endpoint.start();
570
587
  * endpoint.subscribe((event) => { ... });
571
- * await endpoint.emit({ type: "message.request", payload: envelope });
588
+ * await endpoint.emit({ type: NcpEventType.MessageRequest, payload: envelope });
572
589
  */
573
590
  interface NcpEndpoint {
574
591
  /** Static capability declaration — available before `start()` is called. */
@@ -598,7 +615,7 @@ interface NcpEndpoint {
598
615
  *
599
616
  * @example
600
617
  * const unsubscribe = endpoint.subscribe((event) => {
601
- * if (event.type === "message.completed") handleReply(event.payload);
618
+ * if (event.type === NcpEventType.MessageCompleted) handleReply(event.payload);
602
619
  * });
603
620
  * unsubscribe();
604
621
  */
@@ -614,60 +631,222 @@ interface NcpEndpoint {
614
631
  interface NcpAgentClientEndpoint extends NcpEndpoint {
615
632
  /** Sends a new message request to the agent. Emits `message.request`. */
616
633
  send(envelope: NcpRequestEnvelope): Promise<void>;
617
- /** Resumes an existing run by remote run id. Emits `message.resume-request`. */
618
- resume(payload: NcpResumeRequestPayload): Promise<void>;
619
- /** Aborts the current or specified run. Emits `message.abort`. */
620
- abort(payload?: NcpMessageAbortPayload): Promise<void>;
634
+ /** Attaches to the live event stream of a session. Emits `message.stream-request`. */
635
+ stream(payload: NcpStreamRequestPayload): Promise<void>;
636
+ /** Aborts the active execution of a session. Emits `message.abort`. */
637
+ abort(payload: NcpMessageAbortPayload): Promise<void>;
621
638
  }
622
639
 
623
640
  /**
624
- * Agent server-side endpoint: receives requests and emits responses.
641
+ * Agent server-side endpoint: receives requests and produces downstream events.
625
642
  *
626
643
  * Extends `NcpEndpoint` with a manifest constraint (`endpointKind: "agent"`).
627
- * Use this on the server side that processes `message.request` / `message.resume-request`
628
- * and emits `message.incoming`, streaming deltas, `message.completed`, etc.
644
+ * Use this on the server side that handles send/stream/abort requests and emits
645
+ * downstream events (`message.incoming`, streaming deltas, `message.completed`, etc.).
629
646
  */
630
647
  interface NcpAgentServerEndpoint extends NcpEndpoint {
631
648
  readonly manifest: NcpEndpointManifest & {
632
649
  endpointKind: "agent";
633
650
  };
651
+ /** Handles a new message request from client side and yields produced events. */
652
+ send(envelope: NcpRequestEnvelope, options?: {
653
+ signal?: AbortSignal;
654
+ }): AsyncIterable<NcpEndpointEvent>;
655
+ /** Streams live events for an active session and yields produced events. */
656
+ stream(payload: NcpStreamRequestPayload, options?: {
657
+ signal?: AbortSignal;
658
+ }): AsyncIterable<NcpEndpointEvent>;
659
+ /** Aborts the active execution of a session on server side. */
660
+ abort(payload: NcpMessageAbortPayload): Promise<void>;
661
+ /**
662
+ * Publishes server-downstream events (typically sent to frontend subscribers/transports).
663
+ * For handling client requests, prefer `send` / `stream` / `abort`.
664
+ */
665
+ emit(event: NcpEndpointEvent): Promise<void>;
634
666
  }
635
667
 
636
- /**
637
- * Creates an NcpAgentClientEndpoint that forwards to an in-process NcpAgentServerEndpoint.
638
- * Use when the agent runs in-process and you need to pass a client endpoint to the HTTP server.
639
- */
640
- declare function createAgentClientFromServer(server: NcpAgentServerEndpoint): NcpAgentClientEndpoint;
641
-
642
668
  type NcpAgentRunInput = {
643
- kind: "request";
644
- payload: NcpRequestEnvelope;
645
- } | {
646
- kind: "resume";
647
- payload: NcpResumeRequestPayload;
669
+ sessionId: string;
670
+ messages: ReadonlyArray<NcpMessage>;
671
+ correlationId?: string;
672
+ metadata?: Record<string, unknown>;
648
673
  };
649
674
  type NcpAgentRunOptions = {
650
675
  signal?: AbortSignal;
651
- sessionMessages?: ReadonlyArray<NcpMessage>;
652
676
  };
653
677
  interface NcpAgentRuntime {
654
678
  run(input: NcpAgentRunInput, options?: NcpAgentRunOptions): AsyncIterable<NcpEndpointEvent>;
655
679
  }
656
680
 
657
- type NcpAgentBackendSendOptions = {
681
+ type OpenAIContentPart = {
682
+ type: "text";
683
+ text: string;
684
+ } | {
685
+ type: "image_url";
686
+ image_url: {
687
+ url: string;
688
+ detail?: "low" | "high" | "auto";
689
+ };
690
+ };
691
+ type OpenAIToolCall = {
692
+ id: string;
693
+ type: "function";
694
+ function: {
695
+ name: string;
696
+ arguments: string;
697
+ };
698
+ };
699
+ type OpenAIChatMessage = {
700
+ role: "system";
701
+ content: string;
702
+ } | {
703
+ role: "user";
704
+ content: string | OpenAIContentPart[];
705
+ } | {
706
+ role: "assistant";
707
+ content?: string | null;
708
+ reasoning_content?: string;
709
+ tool_calls?: OpenAIToolCall[];
710
+ } | {
711
+ role: "tool";
712
+ content: string;
713
+ tool_call_id: string;
714
+ };
715
+ type OpenAITool = {
716
+ type: "function";
717
+ function: {
718
+ name: string;
719
+ description?: string;
720
+ parameters?: Record<string, unknown>;
721
+ };
722
+ };
723
+ type OpenAIToolCallDelta = {
724
+ index?: number;
725
+ id?: string;
726
+ type?: "function";
727
+ function?: {
728
+ name?: string;
729
+ arguments?: string;
730
+ };
731
+ };
732
+ type OpenAIChatChunk = {
733
+ id?: string;
734
+ choices?: Array<{
735
+ index?: number;
736
+ delta?: {
737
+ content?: string | null;
738
+ tool_calls?: OpenAIToolCallDelta[];
739
+ reasoning_content?: string;
740
+ reasoning?: string;
741
+ };
742
+ finish_reason?: string | null;
743
+ }>;
744
+ usage?: {
745
+ prompt_tokens?: number;
746
+ completion_tokens?: number;
747
+ total_tokens?: number;
748
+ };
749
+ };
750
+ type NcpLLMApiInput = {
751
+ messages: OpenAIChatMessage[];
752
+ tools?: OpenAITool[];
753
+ model?: string;
754
+ thinkingLevel?: string | null;
755
+ max_tokens?: number;
756
+ };
757
+ type NcpLLMApiOptions = {
658
758
  signal?: AbortSignal;
759
+ temperature?: number;
760
+ };
761
+ interface NcpLLMApi {
762
+ generate(input: NcpLLMApiInput, options?: NcpLLMApiOptions): AsyncIterable<OpenAIChatChunk>;
763
+ }
764
+
765
+ type NcpContextPrepareOptions = {
766
+ sessionMessages?: ReadonlyArray<NcpMessage>;
767
+ systemPrompt?: string;
768
+ maxMessages?: number;
769
+ };
770
+ interface NcpContextBuilder {
771
+ prepare(input: NcpAgentRunInput, options?: NcpContextPrepareOptions): NcpLLMApiInput;
772
+ }
773
+
774
+ type NcpToolDefinition = {
775
+ name: string;
776
+ description?: string;
777
+ parameters?: Record<string, unknown>;
778
+ };
779
+ interface NcpTool {
780
+ readonly name: string;
781
+ readonly description?: string;
782
+ readonly parameters?: Record<string, unknown>;
783
+ execute(args: unknown): Promise<unknown>;
784
+ }
785
+ type NcpToolCallResult = {
786
+ toolCallId: string;
787
+ toolName: string;
788
+ args: Record<string, unknown> | null;
789
+ rawArgsText: string;
790
+ result: unknown;
791
+ };
792
+ type NcpInvalidToolArgumentsResult = {
793
+ ok: false;
794
+ error: {
795
+ code: "invalid_tool_arguments";
796
+ message: string;
797
+ toolCallId: string;
798
+ toolName: string;
799
+ rawArgumentsText: string;
800
+ issues: string[];
801
+ };
659
802
  };
660
- type NcpAgentBackendReconnectOptions = {
803
+ interface NcpToolRegistry {
804
+ listTools(): ReadonlyArray<NcpTool>;
805
+ getTool(name: string): NcpTool | undefined;
806
+ getToolDefinitions(): ReadonlyArray<NcpToolDefinition>;
807
+ execute(toolCallId: string, toolName: string, args: unknown): Promise<unknown>;
808
+ }
809
+
810
+ type NcpEncodeContext = {
811
+ sessionId: string;
812
+ messageId: string;
813
+ runId: string;
814
+ correlationId?: string;
815
+ };
816
+ interface NcpStreamEncoder {
817
+ encode(stream: AsyncIterable<OpenAIChatChunk>, context: NcpEncodeContext): AsyncIterable<NcpEndpointEvent>;
818
+ }
819
+
820
+ type NcpPendingToolCall = {
821
+ toolCallId: string;
822
+ toolName: string;
823
+ args: unknown;
824
+ };
825
+ interface NcpRoundBuffer {
826
+ appendText(delta: string): void;
827
+ getText(): string;
828
+ appendToolCall(result: NcpToolCallResult): void;
829
+ getToolCalls(): ReadonlyArray<NcpToolCallResult>;
830
+ startToolCall(toolCallId: string, toolName: string): void;
831
+ appendToolCallArgs(args: unknown): void;
832
+ consumePendingToolCall(): NcpPendingToolCall | null;
833
+ clear(): void;
834
+ }
835
+
836
+ type NcpAgentRunSendOptions = {
837
+ signal?: AbortSignal;
838
+ };
839
+ type NcpAgentRunStreamOptions = {
661
840
  signal?: AbortSignal;
662
841
  };
663
- interface NcpAgentBackendController extends NcpSessionApi {
664
- send(envelope: NcpRequestEnvelope, options?: NcpAgentBackendSendOptions): AsyncIterable<NcpEndpointEvent>;
665
- reconnect(payload: NcpResumeRequestPayload, options?: NcpAgentBackendReconnectOptions): AsyncIterable<NcpEndpointEvent>;
842
+ interface NcpAgentRunApi {
843
+ send(envelope: NcpRequestEnvelope, options?: NcpAgentRunSendOptions): AsyncIterable<NcpEndpointEvent>;
844
+ stream(payload: NcpStreamRequestPayload, options?: NcpAgentRunStreamOptions): AsyncIterable<NcpEndpointEvent>;
666
845
  abort(payload: NcpMessageAbortPayload): Promise<void>;
667
846
  }
668
- type NcpAgentReplayProvider = {
847
+ type NcpAgentStreamProvider = {
669
848
  stream(params: {
670
- payload: NcpResumeRequestPayload;
849
+ payload: NcpStreamRequestPayload;
671
850
  signal: AbortSignal;
672
851
  }): AsyncIterable<NcpEndpointEvent>;
673
852
  };
@@ -716,6 +895,11 @@ interface NcpConversationStateManager {
716
895
  subscribe(listener: (snapshot: NcpConversationSnapshot) => void): () => void;
717
896
  }
718
897
 
898
+ type NcpAgentConversationHydrationParams = {
899
+ sessionId: string;
900
+ messages: ReadonlyArray<NcpMessage>;
901
+ activeRun?: NcpRunContext | null;
902
+ };
719
903
  /**
720
904
  * Agent-scenario state manager: extends the generic conversation state manager
721
905
  * with explicit handle methods for each NCP event type that affects agent conversation state.
@@ -725,13 +909,10 @@ interface NcpConversationStateManager {
725
909
  */
726
910
  interface NcpAgentConversationStateManager extends NcpConversationStateManager {
727
911
  getSnapshot(): NcpAgentConversationSnapshot;
728
- handleMessageRequest(payload: NcpRequestEnvelope): void;
912
+ reset(): void;
913
+ hydrate(payload: NcpAgentConversationHydrationParams): void;
729
914
  /** Local peer sent a message (outbound); typically non-streaming. Add to messages. */
730
915
  handleMessageSent(payload: NcpMessageSentPayload): void;
731
- handleMessageAccepted(payload: NcpMessageAcceptedPayload): void;
732
- handleMessageIncoming(payload: NcpResponseEnvelope): void;
733
- handleMessageCompleted(payload: NcpCompletedEnvelope): void;
734
- handleMessageFailed(payload: NcpFailedEnvelope): void;
735
916
  handleMessageAbort(payload: NcpMessageAbortPayload): void;
736
917
  handleMessageTextStart(payload: NcpTextStartPayload): void;
737
918
  handleMessageTextDelta(payload: NcpTextDeltaPayload): void;
@@ -751,4 +932,11 @@ interface NcpAgentConversationStateManager extends NcpConversationStateManager {
751
932
  handleEndpointError(payload: NcpError): void;
752
933
  }
753
934
 
754
- export { type ListMessagesOptions, type ListSessionsOptions, type NcpActionPart, type NcpAgentBackendController, type NcpAgentBackendReconnectOptions, type NcpAgentBackendSendOptions, type NcpAgentClientEndpoint, type NcpAgentConversationSnapshot, type NcpAgentConversationStateManager, type NcpAgentReplayProvider, type NcpAgentRunInput, type NcpAgentRunOptions, type NcpAgentRuntime, type NcpAgentServerEndpoint, type NcpCardPart, type NcpCompletedEnvelope, type NcpConversationSnapshot, type NcpConversationStateManager, type NcpEndpoint, type NcpEndpointEvent, type NcpEndpointKind, type NcpEndpointLatency, type NcpEndpointManifest, type NcpEndpointSubscriber, type NcpError, type NcpErrorCode, NcpErrorException, type NcpExtensionPart, type NcpFailedEnvelope, type NcpFilePart, type NcpMessage, type NcpMessageAbortPayload, type NcpMessageAcceptedPayload, type NcpMessageDeliveredPayload, type NcpMessagePart, type NcpMessageReactionPayload, type NcpMessageReadPayload, type NcpMessageRecalledPayload, type NcpMessageRole, type NcpMessageSentPayload, type NcpMessageStatus, type NcpPresenceUpdatedPayload, type NcpReasoningDeltaPayload, type NcpReasoningEndPayload, type NcpReasoningPart, type NcpReasoningStartPayload, type NcpRequestEnvelope, type NcpResponseEnvelope, type NcpResumeRequestPayload, type NcpRichTextPart, type NcpRunContext, type NcpRunErrorPayload, type NcpRunFinalMetadata, type NcpRunFinishedPayload, type NcpRunMetadataPayload, type NcpRunReadyMetadata, type NcpRunStartedPayload, type NcpSessionApi, type NcpSessionStatus, type NcpSessionSummary, type NcpSourcePart, type NcpStepStartPart, type NcpTextDeltaPayload, type NcpTextEndPayload, type NcpTextPart, type NcpTextStartPayload, type NcpToolCallArgsDeltaPayload, type NcpToolCallArgsPayload, type NcpToolCallEndPayload, type NcpToolCallResultPayload, type NcpToolCallStartPayload, type NcpToolInvocationPart, type NcpTypingEndPayload, type NcpTypingStartPayload, createAgentClientFromServer };
935
+ type NcpReplyTagParseResult = {
936
+ content: string;
937
+ replyTo?: string;
938
+ };
939
+ declare function stripReplyTagsFromText(content: string, currentMessageId?: string): NcpReplyTagParseResult;
940
+ declare function sanitizeAssistantReplyTags(message: NcpMessage, currentMessageId?: string): NcpMessage;
941
+
942
+ export { type ListMessagesOptions, type ListSessionsOptions, type NcpActionPart, type NcpAgentClientEndpoint, type NcpAgentConversationHydrationParams, type NcpAgentConversationSnapshot, type NcpAgentConversationStateManager, type NcpAgentRunApi, type NcpAgentRunInput, type NcpAgentRunOptions, type NcpAgentRunSendOptions, type NcpAgentRunStreamOptions, type NcpAgentRuntime, type NcpAgentServerEndpoint, type NcpAgentStreamProvider, type NcpCardPart, type NcpCompletedEnvelope, type NcpContextBuilder, type NcpContextPrepareOptions, type NcpConversationSnapshot, type NcpConversationStateManager, type NcpEncodeContext, type NcpEndpoint, type NcpEndpointEvent, type NcpEndpointKind, type NcpEndpointLatency, type NcpEndpointManifest, type NcpEndpointSubscriber, type NcpError, type NcpErrorCode, NcpEventType, type NcpExtensionPart, type NcpFailedEnvelope, type NcpFilePart, type NcpInvalidToolArgumentsResult, type NcpLLMApi, type NcpLLMApiInput, type NcpLLMApiOptions, type NcpMessage, type NcpMessageAbortPayload, type NcpMessageAcceptedPayload, type NcpMessageDeliveredPayload, type NcpMessagePart, type NcpMessageReactionPayload, type NcpMessageReadPayload, type NcpMessageRecalledPayload, type NcpMessageRole, type NcpMessageSentPayload, type NcpMessageStatus, type NcpPendingToolCall, type NcpPresenceUpdatedPayload, type NcpReasoningDeltaPayload, type NcpReasoningEndPayload, type NcpReasoningPart, type NcpReasoningStartPayload, type NcpReplyTagParseResult, type NcpRequestEnvelope, type NcpResponseEnvelope, type NcpRichTextPart, type NcpRoundBuffer, type NcpRunContext, type NcpRunErrorPayload, type NcpRunFinalMetadata, type NcpRunFinishedPayload, type NcpRunMetadataPayload, type NcpRunReadyMetadata, type NcpRunStartedPayload, type NcpSessionApi, type NcpSessionStatus, type NcpSessionSummary, type NcpSourcePart, type NcpStepStartPart, type NcpStreamEncoder, type NcpStreamRequestPayload, type NcpTextDeltaPayload, type NcpTextEndPayload, type NcpTextPart, type NcpTextStartPayload, type NcpTool, type NcpToolCallArgsDeltaPayload, type NcpToolCallArgsPayload, type NcpToolCallEndPayload, type NcpToolCallResult, type NcpToolCallResultPayload, type NcpToolCallStartPayload, type NcpToolDefinition, type NcpToolInvocationPart, type NcpToolRegistry, type NcpTypingEndPayload, type NcpTypingStartPayload, type OpenAIChatChunk, type OpenAIChatMessage, type OpenAIContentPart, type OpenAITool, type OpenAIToolCall, type OpenAIToolCallDelta, sanitizeAssistantReplyTags, stripReplyTagsFromText };
package/dist/index.js CHANGED
@@ -1,31 +1,119 @@
1
- // src/types/errors.ts
2
- var NcpErrorException = class extends Error {
3
- code;
4
- details;
5
- constructor(code, message, details) {
6
- super(message);
7
- this.name = "NcpErrorException";
8
- this.code = code;
9
- this.details = details;
10
- }
11
- };
1
+ // src/types/events.ts
2
+ var NcpEventType = /* @__PURE__ */ ((NcpEventType2) => {
3
+ NcpEventType2["EndpointReady"] = "endpoint.ready";
4
+ NcpEventType2["EndpointError"] = "endpoint.error";
5
+ NcpEventType2["MessageRequest"] = "message.request";
6
+ NcpEventType2["MessageStreamRequest"] = "message.stream-request";
7
+ NcpEventType2["MessageSent"] = "message.sent";
8
+ NcpEventType2["MessageAccepted"] = "message.accepted";
9
+ NcpEventType2["MessageIncoming"] = "message.incoming";
10
+ NcpEventType2["MessageCompleted"] = "message.completed";
11
+ NcpEventType2["MessageFailed"] = "message.failed";
12
+ NcpEventType2["MessageAbort"] = "message.abort";
13
+ NcpEventType2["MessageTextStart"] = "message.text-start";
14
+ NcpEventType2["MessageTextDelta"] = "message.text-delta";
15
+ NcpEventType2["MessageTextEnd"] = "message.text-end";
16
+ NcpEventType2["MessageReasoningStart"] = "message.reasoning-start";
17
+ NcpEventType2["MessageReasoningDelta"] = "message.reasoning-delta";
18
+ NcpEventType2["MessageReasoningEnd"] = "message.reasoning-end";
19
+ NcpEventType2["MessageToolCallStart"] = "message.tool-call-start";
20
+ NcpEventType2["MessageToolCallArgs"] = "message.tool-call-args";
21
+ NcpEventType2["MessageToolCallArgsDelta"] = "message.tool-call-args-delta";
22
+ NcpEventType2["MessageToolCallEnd"] = "message.tool-call-end";
23
+ NcpEventType2["MessageToolCallResult"] = "message.tool-call-result";
24
+ NcpEventType2["MessageRead"] = "message.read";
25
+ NcpEventType2["MessageDelivered"] = "message.delivered";
26
+ NcpEventType2["MessageRecalled"] = "message.recalled";
27
+ NcpEventType2["MessageReaction"] = "message.reaction";
28
+ NcpEventType2["RunStarted"] = "run.started";
29
+ NcpEventType2["RunFinished"] = "run.finished";
30
+ NcpEventType2["RunError"] = "run.error";
31
+ NcpEventType2["RunMetadata"] = "run.metadata";
32
+ NcpEventType2["TypingStart"] = "typing.start";
33
+ NcpEventType2["TypingEnd"] = "typing.end";
34
+ NcpEventType2["PresenceUpdated"] = "presence.updated";
35
+ return NcpEventType2;
36
+ })(NcpEventType || {});
12
37
 
13
- // src/endpoint/agent-client-from-server.ts
14
- function createAgentClientFromServer(server) {
15
- return {
16
- ...server,
17
- async send(envelope) {
18
- await server.emit({ type: "message.request", payload: envelope });
19
- },
20
- async resume(payload) {
21
- await server.emit({ type: "message.resume-request", payload });
22
- },
23
- async abort(payload) {
24
- await server.emit({ type: "message.abort", payload: payload ?? {} });
38
+ // src/toolkit/reply-tags.ts
39
+ var REPLY_TO_CURRENT_PATTERN = /\[\[\s*reply_to_current\s*\]\]/gi;
40
+ var REPLY_TO_ID_PATTERN = /\[\[\s*reply_to\s*:\s*([^\]]+?)\s*\]\]/i;
41
+ function normalizeReplyTarget(value) {
42
+ if (typeof value !== "string") {
43
+ return void 0;
44
+ }
45
+ const trimmed = value.trim();
46
+ return trimmed.length > 0 ? trimmed : void 0;
47
+ }
48
+ function stripReplyTagsFromText(content, currentMessageId) {
49
+ let nextContent = content;
50
+ let replyTo;
51
+ if (REPLY_TO_CURRENT_PATTERN.test(nextContent)) {
52
+ replyTo = normalizeReplyTarget(currentMessageId);
53
+ nextContent = nextContent.replace(REPLY_TO_CURRENT_PATTERN, "").trim();
54
+ }
55
+ const explicitReplyTarget = nextContent.match(REPLY_TO_ID_PATTERN)?.[1];
56
+ if (explicitReplyTarget) {
57
+ replyTo = normalizeReplyTarget(explicitReplyTarget);
58
+ nextContent = nextContent.replace(REPLY_TO_ID_PATTERN, "").trim();
59
+ }
60
+ return replyTo ? { content: nextContent, replyTo } : { content: nextContent };
61
+ }
62
+ function sanitizeAssistantReplyTags(message, currentMessageId = message.id) {
63
+ if (message.role !== "assistant") {
64
+ return {
65
+ ...message,
66
+ parts: [...message.parts],
67
+ metadata: message.metadata ? { ...message.metadata } : void 0
68
+ };
69
+ }
70
+ const firstTextIndex = message.parts.findIndex((part) => part.type === "text");
71
+ const nextMetadata = message.metadata ? { ...message.metadata } : void 0;
72
+ const existingReplyTo = normalizeReplyTarget(nextMetadata?.reply_to);
73
+ if (firstTextIndex < 0) {
74
+ return {
75
+ ...message,
76
+ parts: [...message.parts],
77
+ metadata: nextMetadata
78
+ };
79
+ }
80
+ const firstTextPart = message.parts[firstTextIndex];
81
+ if (!firstTextPart || firstTextPart.type !== "text") {
82
+ return {
83
+ ...message,
84
+ parts: [...message.parts],
85
+ metadata: nextMetadata
86
+ };
87
+ }
88
+ const { content, replyTo } = stripReplyTagsFromText(firstTextPart.text, currentMessageId);
89
+ const effectiveReplyTo = replyTo ?? existingReplyTo;
90
+ const nextParts = message.parts.flatMap((part, index) => {
91
+ if (index !== firstTextIndex || part.type !== "text") {
92
+ return [part];
25
93
  }
94
+ if (content.length === 0) {
95
+ return [];
96
+ }
97
+ return [{ ...part, text: content }];
98
+ });
99
+ if (effectiveReplyTo) {
100
+ return {
101
+ ...message,
102
+ parts: nextParts,
103
+ metadata: {
104
+ ...nextMetadata,
105
+ reply_to: effectiveReplyTo
106
+ }
107
+ };
108
+ }
109
+ return {
110
+ ...message,
111
+ parts: nextParts,
112
+ metadata: nextMetadata
26
113
  };
27
114
  }
28
115
  export {
29
- NcpErrorException,
30
- createAgentClientFromServer
116
+ NcpEventType,
117
+ sanitizeAssistantReplyTags,
118
+ stripReplyTagsFromText
31
119
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/ncp",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "description": "NextClaw Communication Protocol core abstractions and types.",
6
6
  "type": "module",
@@ -16,10 +16,6 @@
16
16
  ],
17
17
  "devDependencies": {
18
18
  "@types/node": "^20.17.6",
19
- "@typescript-eslint/eslint-plugin": "^7.18.0",
20
- "@typescript-eslint/parser": "^7.18.0",
21
- "eslint": "^8.57.1",
22
- "eslint-config-prettier": "^9.1.0",
23
19
  "prettier": "^3.3.3",
24
20
  "tsup": "^8.3.5",
25
21
  "typescript": "^5.6.3"