xcode-copilot-server 1.0.4 → 2.0.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.
Files changed (102) hide show
  1. package/README.md +56 -29
  2. package/config.json5 +49 -41
  3. package/dist/config.d.ts +8 -4
  4. package/dist/config.js +14 -7
  5. package/dist/config.js.map +1 -1
  6. package/dist/context.d.ts +1 -0
  7. package/dist/conversation-manager.d.ts +32 -0
  8. package/dist/conversation-manager.js +120 -0
  9. package/dist/conversation-manager.js.map +1 -0
  10. package/dist/copilot-service.d.ts +1 -3
  11. package/dist/copilot-service.js +3 -23
  12. package/dist/copilot-service.js.map +1 -1
  13. package/dist/handlers/completions/streaming.d.ts +1 -1
  14. package/dist/handlers/completions/streaming.js +13 -24
  15. package/dist/handlers/completions/streaming.js.map +1 -1
  16. package/dist/handlers/completions.d.ts +2 -2
  17. package/dist/handlers/completions.js +75 -63
  18. package/dist/handlers/completions.js.map +1 -1
  19. package/dist/handlers/errors.d.ts +5 -0
  20. package/dist/handlers/errors.js +10 -0
  21. package/dist/handlers/errors.js.map +1 -0
  22. package/dist/handlers/messages/count-tokens.d.ts +3 -0
  23. package/dist/handlers/messages/count-tokens.js +72 -0
  24. package/dist/handlers/messages/count-tokens.js.map +1 -0
  25. package/dist/handlers/messages/streaming.d.ts +6 -0
  26. package/dist/handlers/messages/streaming.js +274 -0
  27. package/dist/handlers/messages/streaming.js.map +1 -0
  28. package/dist/handlers/messages/tool-result-handler.d.ts +4 -0
  29. package/dist/handlers/messages/tool-result-handler.js +19 -0
  30. package/dist/handlers/messages/tool-result-handler.js.map +1 -0
  31. package/dist/handlers/messages.d.ts +4 -0
  32. package/dist/handlers/messages.js +150 -0
  33. package/dist/handlers/messages.js.map +1 -0
  34. package/dist/handlers/models.d.ts +0 -1
  35. package/dist/handlers/models.js +1 -2
  36. package/dist/handlers/models.js.map +1 -1
  37. package/dist/handlers/session-config.d.ts +15 -0
  38. package/dist/handlers/session-config.js +79 -0
  39. package/dist/handlers/session-config.js.map +1 -0
  40. package/dist/handlers/streaming-utils.d.ts +9 -0
  41. package/dist/handlers/streaming-utils.js +19 -0
  42. package/dist/handlers/streaming-utils.js.map +1 -0
  43. package/dist/index.js +18 -4
  44. package/dist/index.js.map +1 -1
  45. package/dist/logger.d.ts +0 -1
  46. package/dist/logger.js +4 -10
  47. package/dist/logger.js.map +1 -1
  48. package/dist/providers/anthropic.d.ts +5 -0
  49. package/dist/providers/anthropic.js +28 -0
  50. package/dist/providers/anthropic.js.map +1 -0
  51. package/dist/providers/index.d.ts +15 -0
  52. package/dist/providers/index.js +7 -0
  53. package/dist/providers/index.js.map +1 -0
  54. package/dist/providers/openai.d.ts +5 -0
  55. package/dist/providers/openai.js +25 -0
  56. package/dist/providers/openai.js.map +1 -0
  57. package/dist/providers/types.d.ts +7 -0
  58. package/dist/providers/types.js +2 -0
  59. package/dist/providers/types.js.map +1 -0
  60. package/dist/schemas/anthropic.d.ts +140 -0
  61. package/dist/schemas/anthropic.js +58 -0
  62. package/dist/schemas/anthropic.js.map +1 -0
  63. package/dist/schemas/config.d.ts +127 -0
  64. package/dist/schemas/config.js +44 -0
  65. package/dist/schemas/config.js.map +1 -0
  66. package/dist/schemas/openai.d.ts +98 -0
  67. package/dist/schemas/openai.js +76 -0
  68. package/dist/schemas/openai.js.map +1 -0
  69. package/dist/server.d.ts +2 -1
  70. package/dist/server.js +11 -20
  71. package/dist/server.js.map +1 -1
  72. package/dist/tool-bridge/index.d.ts +4 -0
  73. package/dist/tool-bridge/index.js +8 -0
  74. package/dist/tool-bridge/index.js.map +1 -0
  75. package/dist/tool-bridge/reply-tracker.d.ts +10 -0
  76. package/dist/tool-bridge/reply-tracker.js +28 -0
  77. package/dist/tool-bridge/reply-tracker.js.map +1 -0
  78. package/dist/tool-bridge/routes.d.ts +4 -0
  79. package/dist/tool-bridge/routes.js +111 -0
  80. package/dist/tool-bridge/routes.js.map +1 -0
  81. package/dist/tool-bridge/session-lifecycle.d.ts +16 -0
  82. package/dist/tool-bridge/session-lifecycle.js +43 -0
  83. package/dist/tool-bridge/session-lifecycle.js.map +1 -0
  84. package/dist/tool-bridge/state.d.ts +34 -0
  85. package/dist/tool-bridge/state.js +77 -0
  86. package/dist/tool-bridge/state.js.map +1 -0
  87. package/dist/tool-bridge/tool-cache.d.ts +10 -0
  88. package/dist/tool-bridge/tool-cache.js +82 -0
  89. package/dist/tool-bridge/tool-cache.js.map +1 -0
  90. package/dist/tool-bridge/tool-router.d.ts +12 -0
  91. package/dist/tool-bridge/tool-router.js +82 -0
  92. package/dist/tool-bridge/tool-router.js.map +1 -0
  93. package/dist/utils/anthropic-prompt.d.ts +2 -0
  94. package/dist/utils/anthropic-prompt.js +52 -0
  95. package/dist/utils/anthropic-prompt.js.map +1 -0
  96. package/dist/utils/model-resolver.d.ts +3 -0
  97. package/dist/utils/model-resolver.js +45 -0
  98. package/dist/utils/model-resolver.js.map +1 -0
  99. package/dist/utils/prompt.d.ts +2 -14
  100. package/dist/utils/prompt.js +11 -14
  101. package/dist/utils/prompt.js.map +1 -1
  102. package/package.json +5 -4
@@ -1,13 +1,8 @@
1
- import { truncate } from "../../logger.js";
2
- import { currentTimestamp } from "../../schemas.js";
1
+ import { formatCompaction, SSE_HEADERS } from "../streaming-utils.js";
2
+ import { currentTimestamp } from "../../schemas/openai.js";
3
3
  const REQUEST_TIMEOUT_MS = 5 * 60 * 1000;
4
4
  export async function handleStreaming(reply, session, prompt, model, logger) {
5
- reply.raw.writeHead(200, {
6
- "Content-Type": "text/event-stream",
7
- "Cache-Control": "no-cache",
8
- Connection: "keep-alive",
9
- "X-Accel-Buffering": "no",
10
- });
5
+ reply.raw.writeHead(200, SSE_HEADERS);
11
6
  const completionId = `chatcmpl-${String(Date.now())}`;
12
7
  function sendChunk(delta, finishReason) {
13
8
  const chunk = {
@@ -40,19 +35,17 @@ export async function handleStreaming(reply, session, prompt, model, logger) {
40
35
  session.abort().catch((err) => {
41
36
  logger.error("Failed to abort session:", err);
42
37
  });
43
- resolve(undefined);
38
+ resolve(false);
44
39
  }
45
40
  });
46
41
  const timeout = setTimeout(() => {
47
42
  logger.warn("Stream timed out after 5 minutes");
48
43
  cleanup();
49
44
  reply.raw.end();
50
- resolve(undefined);
45
+ resolve(false);
51
46
  }, REQUEST_TIMEOUT_MS);
52
- // Buffer deltas so we can discard intermediate narration
53
- // (e.g. "Let me search...") that precedes tool calls.
47
+ // buffer deltas so we can drop intermediate narration before tool calls
54
48
  let pendingDeltas = [];
55
- // Track tool names by call ID so we can log them on completion
56
49
  const toolNames = new Map();
57
50
  function flushPending() {
58
51
  for (const text of pendingDeltas) {
@@ -64,7 +57,7 @@ export async function handleStreaming(reply, session, prompt, model, logger) {
64
57
  if (event.type === "tool.execution_start") {
65
58
  const d = event.data;
66
59
  toolNames.set(d.toolCallId, d.toolName);
67
- logger.debug(`Running ${d.toolName} (${truncate(d.arguments)})`);
60
+ logger.debug(`Running ${d.toolName} (${JSON.stringify(d.arguments)})`);
68
61
  return;
69
62
  }
70
63
  if (event.type === "tool.execution_complete") {
@@ -72,7 +65,7 @@ export async function handleStreaming(reply, session, prompt, model, logger) {
72
65
  const name = toolNames.get(d.toolCallId) ?? d.toolCallId;
73
66
  toolNames.delete(d.toolCallId);
74
67
  const detail = d.success
75
- ? truncate(d.result?.content)
68
+ ? JSON.stringify(d.result?.content)
76
69
  : d.error?.message ?? "failed";
77
70
  logger.debug(`${name} done (${detail})`);
78
71
  return;
@@ -85,12 +78,10 @@ export async function handleStreaming(reply, session, prompt, model, logger) {
85
78
  break;
86
79
  case "assistant.message":
87
80
  if (event.data.toolRequests && event.data.toolRequests.length > 0) {
88
- // Intermediate turn, so discard buffered narration.
89
81
  logger.debug(`Calling tools (dropping buffered text): ${event.data.toolRequests.map((tr) => tr.name).join(", ")}`);
90
82
  pendingDeltas = [];
91
83
  }
92
84
  else {
93
- // Final turn, so flush buffered deltas to the client.
94
85
  flushPending();
95
86
  }
96
87
  break;
@@ -101,21 +92,19 @@ export async function handleStreaming(reply, session, prompt, model, logger) {
101
92
  sendChunk({}, "stop");
102
93
  reply.raw.write("data: [DONE]\n\n");
103
94
  reply.raw.end();
104
- resolve(undefined);
95
+ resolve(true);
105
96
  break;
106
97
  case "session.compaction_start":
107
98
  logger.info("Compacting context...");
108
99
  break;
109
- case "session.compaction_complete": {
110
- const cd = event.data;
111
- logger.info(`Context compacted: ${String(cd.preCompactionTokens)} → ${String(cd.postCompactionTokens)} tokens`);
100
+ case "session.compaction_complete":
101
+ logger.info(`Context compacted: ${formatCompaction(event.data)}`);
112
102
  break;
113
- }
114
103
  case "session.error":
115
104
  logger.error(`Session error: ${event.data.message}`);
116
105
  cleanup();
117
106
  reply.raw.end();
118
- resolve(undefined);
107
+ resolve(false);
119
108
  break;
120
109
  }
121
110
  });
@@ -125,7 +114,7 @@ export async function handleStreaming(reply, session, prompt, model, logger) {
125
114
  cleanup();
126
115
  reply.raw.end();
127
116
  }
128
- resolve(undefined);
117
+ resolve(false);
129
118
  });
130
119
  return promise;
131
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../../src/handlers/completions/streaming.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../../src/handlers/completions/streaming.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAwD,MAAM,yBAAyB,CAAC;AAEjH,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,KAAmB,EACnB,OAAuB,EACvB,MAAc,EACd,KAAa,EACb,MAAc;IAEd,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAEtC,MAAM,YAAY,GAAG,YAAY,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;IAEtD,SAAS,SAAS,CAChB,KAAqC,EACrC,YAA2B;QAE3B,MAAM,KAAK,GAAG;YACZ,EAAE,EAAE,YAAY;YAChB,MAAM,EAAE,uBAAgC;YACxC,OAAO,EAAE,gBAAgB,EAAE;YAC3B,KAAK;YACL,OAAO,EAAE;gBACP;oBACE,KAAK,EAAE,CAAC;oBACR,KAAK;oBACL,aAAa,EAAE,YAAY;iBAC5B;aACF;SAC4B,CAAC;QAChC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC;IAEvC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAW,CAAC;IAC9D,IAAI,IAAI,GAAG,KAAK,CAAC;IAEjB,SAAS,OAAO;QACd,IAAI,GAAG,IAAI,CAAC;QACZ,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,WAAW,EAAE,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACzB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;YACrD,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;gBACrC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO,EAAE,CAAC;QACV,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC,EAAE,kBAAkB,CAAC,CAAC;IAEvB,wEAAwE;IACxE,IAAI,aAAa,GAAa,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,SAAS,YAAY;QACnB,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;QACrC,CAAC;QACD,aAAa,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE;QACvC,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;YACrB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CACV,WAAW,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CACzD,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,yBAAyB,EAAE,CAAC;YAC7C,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;YACrB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC;YACzD,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO;gBACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;gBACnC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,CAAC;YACjC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,UAAU,MAAM,GAAG,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,yBAAyB;gBAC5B,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;oBAC5B,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC9C,CAAC;gBACD,MAAM;YAER,KAAK,mBAAmB;gBACtB,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClE,MAAM,CAAC,KAAK,CACV,2CAA2C,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrG,CAAC;oBACF,aAAa,GAAG,EAAE,CAAC;gBACrB,CAAC;qBAAM,CAAC;oBACN,YAAY,EAAE,CAAC;gBACjB,CAAC;gBACD,MAAM;YAER,KAAK,cAAc;gBACjB,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;gBACxC,YAAY,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;gBACV,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBACtB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBACpC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;gBAChB,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM;YAER,KAAK,0BAA0B;gBAC7B,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;gBACrC,MAAM;YAER,KAAK,6BAA6B;gBAChC,MAAM,CAAC,IAAI,CAAC,sBAAsB,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAClE,MAAM;YAER,KAAK,eAAe;gBAClB,MAAM,CAAC,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrD,OAAO,EAAE,CAAC;gBACV,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,CAAC;gBACf,MAAM;QACV,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC9C,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import type { FastifyRequest, FastifyReply } from "fastify";
2
2
  import type { AppContext } from "../context.js";
3
- /** POST /v1/chat/completions */
4
- export declare function createCompletionsHandler({ service, logger, config }: AppContext): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
3
+ import type { ConversationManager } from "../conversation-manager.js";
4
+ export declare function createCompletionsHandler({ service, logger, config }: AppContext, manager: ConversationManager): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
@@ -1,24 +1,24 @@
1
- import { ChatCompletionRequestSchema, extractContentText } from "../schemas.js";
1
+ import { ChatCompletionRequestSchema, extractContentText } from "../schemas/openai.js";
2
2
  import { formatPrompt } from "../utils/prompt.js";
3
- import { createSessionConfig } from "./completions/session-config.js";
3
+ import { createSessionConfig } from "./session-config.js";
4
4
  import { handleStreaming } from "./completions/streaming.js";
5
- /** POST /v1/chat/completions */
6
- export function createCompletionsHandler({ service, logger, config }) {
7
- let sentMessageCount = 0;
5
+ import { sendOpenAIError as sendError } from "./errors.js";
6
+ export function createCompletionsHandler({ service, logger, config }, manager) {
8
7
  return async function handleCompletions(request, reply) {
9
8
  const parseResult = ChatCompletionRequestSchema.safeParse(request.body);
10
9
  if (!parseResult.success) {
11
10
  const firstIssue = parseResult.error.issues[0];
12
- reply.status(400).send({
13
- error: {
14
- message: firstIssue?.message ?? "Invalid request body",
15
- type: "invalid_request_error",
16
- },
17
- });
11
+ sendError(reply, 400, "invalid_request_error", firstIssue?.message ?? "Invalid request body");
18
12
  return;
19
13
  }
20
14
  const req = parseResult.data;
21
15
  const messages = req.messages;
16
+ const { conversation, isReuse } = manager.findForNewRequest();
17
+ const state = conversation.state;
18
+ state.markSessionActive();
19
+ logger.info(isReuse
20
+ ? `Reusing primary conversation ${conversation.id}`
21
+ : `New conversation ${conversation.id}`);
22
22
  const systemParts = [];
23
23
  for (const msg of messages) {
24
24
  if (msg.role === "system" || msg.role === "developer") {
@@ -26,81 +26,93 @@ export function createCompletionsHandler({ service, logger, config }) {
26
26
  systemParts.push(extractContentText(msg.content));
27
27
  }
28
28
  catch (err) {
29
- reply.status(400).send({
30
- error: {
31
- message: err instanceof Error ? err.message : String(err),
32
- type: "invalid_request_error",
33
- },
34
- });
29
+ sendError(reply, 400, "invalid_request_error", err instanceof Error ? err.message : String(err));
30
+ if (isReuse) {
31
+ state.markSessionInactive();
32
+ }
33
+ else {
34
+ manager.remove(conversation.id);
35
+ }
35
36
  return;
36
37
  }
37
38
  }
38
39
  }
39
40
  let prompt;
40
41
  try {
41
- prompt = formatPrompt(messages.slice(sentMessageCount), config.excludedFilePatterns);
42
+ prompt = formatPrompt(messages.slice(conversation.sentMessageCount), config.excludedFilePatterns);
42
43
  }
43
44
  catch (err) {
44
- reply.status(400).send({
45
- error: {
46
- message: err instanceof Error ? err.message : String(err),
47
- type: "invalid_request_error",
48
- },
49
- });
45
+ sendError(reply, 400, "invalid_request_error", err instanceof Error ? err.message : String(err));
46
+ if (isReuse) {
47
+ state.markSessionInactive();
48
+ }
49
+ else {
50
+ manager.remove(conversation.id);
51
+ }
50
52
  return;
51
53
  }
52
- const systemMessage = systemParts.length > 0 ? systemParts.join("\n\n") : undefined;
53
- let supportsReasoningEffort = false;
54
- if (config.reasoningEffort) {
55
- try {
56
- const models = await service.listModels();
57
- const modelInfo = models.find((m) => m.id === req.model);
58
- supportsReasoningEffort =
59
- modelInfo?.capabilities.supports.reasoningEffort ?? false;
60
- if (!supportsReasoningEffort) {
61
- logger.debug(`Model "${req.model}" does not support reasoning effort, ignoring config`);
54
+ if (!isReuse) {
55
+ const systemMessage = systemParts.length > 0 ? systemParts.join("\n\n") : undefined;
56
+ let supportsReasoningEffort = false;
57
+ if (config.reasoningEffort) {
58
+ try {
59
+ const models = await service.listModels();
60
+ const modelInfo = models.find((m) => m.id === req.model);
61
+ supportsReasoningEffort =
62
+ modelInfo?.capabilities.supports.reasoningEffort ?? false;
63
+ if (!supportsReasoningEffort) {
64
+ logger.debug(`Model "${req.model}" does not support reasoning effort, ignoring config`);
65
+ }
66
+ }
67
+ catch (err) {
68
+ logger.warn("Failed to check model capabilities:", err);
62
69
  }
63
70
  }
71
+ // No resolveModel() needed here because Xcode picks from the
72
+ // /v1/models response which already has Copilot's exact IDs
73
+ const sessionConfig = createSessionConfig({
74
+ model: req.model,
75
+ systemMessage,
76
+ logger,
77
+ config,
78
+ supportsReasoningEffort,
79
+ cwd: service.cwd,
80
+ });
81
+ try {
82
+ conversation.session = await service.createSession(sessionConfig);
83
+ }
64
84
  catch (err) {
65
- logger.warn("Failed to check model capabilities:", err);
85
+ logger.error("Creating session failed:", err);
86
+ sendError(reply, 500, "api_error", "Failed to create session");
87
+ manager.remove(conversation.id);
88
+ return;
66
89
  }
67
90
  }
68
- const sessionConfig = createSessionConfig({
69
- model: req.model,
70
- systemMessage,
71
- logger,
72
- config,
73
- supportsReasoningEffort,
74
- cwd: service.cwd,
75
- });
76
- let session;
77
- try {
78
- session = await service.getSession(sessionConfig);
79
- }
80
- catch (err) {
81
- logger.error("Getting session failed:", err);
82
- reply.status(500).send({
83
- error: {
84
- message: "Failed to create session",
85
- type: "api_error",
86
- },
87
- });
91
+ if (!conversation.session) {
92
+ logger.error("Primary conversation has no session, clearing");
93
+ manager.clearPrimary();
94
+ sendError(reply, 500, "api_error", "Session lost, please retry");
88
95
  return;
89
96
  }
90
97
  try {
91
98
  logger.info("Streaming response");
92
- await handleStreaming(reply, session, prompt, req.model, logger);
93
- sentMessageCount = req.messages.length;
99
+ const healthy = await handleStreaming(reply, conversation.session, prompt, req.model, logger);
100
+ state.markSessionInactive();
101
+ if (healthy) {
102
+ conversation.sentMessageCount = req.messages.length;
103
+ }
104
+ else if (conversation.isPrimary) {
105
+ manager.clearPrimary();
106
+ }
94
107
  }
95
108
  catch (err) {
96
109
  logger.error("Request failed:", err);
110
+ state.markSessionInactive();
111
+ if (conversation.isPrimary) {
112
+ manager.clearPrimary();
113
+ }
97
114
  if (!reply.sent) {
98
- reply.status(500).send({
99
- error: {
100
- message: err instanceof Error ? err.message : "Internal error",
101
- type: "api_error",
102
- },
103
- });
115
+ sendError(reply, 500, "api_error", err instanceof Error ? err.message : "Internal error");
104
116
  }
105
117
  }
106
118
  };
@@ -1 +1 @@
1
- {"version":3,"file":"completions.js","sourceRoot":"","sources":["../../src/handlers/completions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"completions.js","sourceRoot":"","sources":["../../src/handlers/completions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { FastifyReply } from "fastify";
2
+ type ErrorType = "invalid_request_error" | "api_error";
3
+ export declare function sendOpenAIError(reply: FastifyReply, status: number, type: ErrorType, message: string): void;
4
+ export declare function sendAnthropicError(reply: FastifyReply, status: number, type: ErrorType, message: string): void;
5
+ export {};
@@ -0,0 +1,10 @@
1
+ export function sendOpenAIError(reply, status, type, message) {
2
+ reply.status(status).send({ error: { message, type } });
3
+ }
4
+ export function sendAnthropicError(reply, status, type, message) {
5
+ reply.status(status).send({
6
+ type: "error",
7
+ error: { type, message },
8
+ });
9
+ }
10
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/handlers/errors.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,eAAe,CAC7B,KAAmB,EACnB,MAAc,EACd,IAAe,EACf,OAAe;IAEf,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAmB,EACnB,MAAc,EACd,IAAe,EACf,OAAe;IAEf,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;QACxB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;KACzB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { FastifyRequest, FastifyReply } from "fastify";
2
+ import type { AppContext } from "../../context.js";
3
+ export declare function createCountTokensHandler({ logger }: AppContext): (request: FastifyRequest, reply: FastifyReply) => void;
@@ -0,0 +1,72 @@
1
+ import { estimateTokenCount } from "tokenx";
2
+ import { AnthropicMessagesRequestSchema, } from "../../schemas/anthropic.js";
3
+ import { sendAnthropicError } from "../errors.js";
4
+ // The token estimator needs a single string, so we pull all text out of
5
+ // the structured request.
6
+ function extractAllText(req) {
7
+ const parts = [];
8
+ if (req.system != null) {
9
+ if (typeof req.system === "string") {
10
+ parts.push(req.system);
11
+ }
12
+ else {
13
+ for (const block of req.system) {
14
+ parts.push(block.text);
15
+ }
16
+ }
17
+ }
18
+ for (const msg of req.messages) {
19
+ if (typeof msg.content === "string") {
20
+ parts.push(msg.content);
21
+ }
22
+ else {
23
+ for (const block of msg.content) {
24
+ switch (block.type) {
25
+ case "text":
26
+ parts.push(block.text);
27
+ break;
28
+ case "tool_use":
29
+ parts.push(block.name);
30
+ parts.push(JSON.stringify(block.input));
31
+ break;
32
+ case "tool_result":
33
+ if (typeof block.content === "string") {
34
+ parts.push(block.content);
35
+ }
36
+ else if (Array.isArray(block.content)) {
37
+ for (const tb of block.content) {
38
+ parts.push(tb.text);
39
+ }
40
+ }
41
+ break;
42
+ default:
43
+ throw block;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ if (req.tools) {
49
+ for (const tool of req.tools) {
50
+ parts.push(tool.name);
51
+ if (tool.description)
52
+ parts.push(tool.description);
53
+ parts.push(JSON.stringify(tool.input_schema));
54
+ }
55
+ }
56
+ return parts.join(" ");
57
+ }
58
+ export function createCountTokensHandler({ logger }) {
59
+ return function handleCountTokens(request, reply) {
60
+ const parseResult = AnthropicMessagesRequestSchema.safeParse(request.body);
61
+ if (!parseResult.success) {
62
+ const firstIssue = parseResult.error.issues[0];
63
+ sendAnthropicError(reply, 400, "invalid_request_error", firstIssue?.message ?? "Invalid request body");
64
+ return;
65
+ }
66
+ const allText = extractAllText(parseResult.data);
67
+ const inputTokens = estimateTokenCount(allText);
68
+ logger.debug(`Token count estimate: ${String(inputTokens)}`);
69
+ void reply.send({ input_tokens: inputTokens });
70
+ };
71
+ }
72
+ //# sourceMappingURL=count-tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"count-tokens.js","sourceRoot":"","sources":["../../../src/handlers/messages/count-tokens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { FastifyReply } from "fastify";
2
+ import type { CopilotSession } from "@github/copilot-sdk";
3
+ import type { Logger } from "../../logger.js";
4
+ import type { ToolBridgeState } from "../../tool-bridge/state.js";
5
+ export declare function startReply(reply: FastifyReply, model: string): void;
6
+ export declare function handleAnthropicStreaming(state: ToolBridgeState, session: CopilotSession, prompt: string, model: string, logger: Logger, hasBridge?: boolean): Promise<void>;