@code-yeongyu/senpi 2026.9.11 → 2026.9.12-2

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 (156) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  3. package/dist/core/agent-session-runtime.js +5 -1
  4. package/dist/core/agent-session-runtime.js.map +1 -1
  5. package/dist/core/agent-session.d.ts +13 -9
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +54 -121
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/cursor-history-admission.d.ts +50 -0
  10. package/dist/core/cursor-history-admission.d.ts.map +1 -0
  11. package/dist/core/cursor-history-admission.js +130 -0
  12. package/dist/core/cursor-history-admission.js.map +1 -0
  13. package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
  14. package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +2 -1
  15. package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
  16. package/dist/core/session-manager.d.ts +2 -0
  17. package/dist/core/session-manager.d.ts.map +1 -1
  18. package/dist/core/session-manager.js +22 -13
  19. package/dist/core/session-manager.js.map +1 -1
  20. package/dist/core/session-write-reservation.d.ts +9 -0
  21. package/dist/core/session-write-reservation.d.ts.map +1 -1
  22. package/dist/core/session-write-reservation.js +33 -0
  23. package/dist/core/session-write-reservation.js.map +1 -1
  24. package/dist/modes/interactive/components/ask-user-async-widget.d.ts +2 -0
  25. package/dist/modes/interactive/components/ask-user-async-widget.d.ts.map +1 -1
  26. package/dist/modes/interactive/components/ask-user-async-widget.js +17 -1
  27. package/dist/modes/interactive/components/ask-user-async-widget.js.map +1 -1
  28. package/dist/modes/interactive/interactive-mode.js +2 -2
  29. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  30. package/dist/modes/rpc/rpc-types.d.ts +2 -1
  31. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  32. package/dist/modes/rpc/rpc-types.js +1 -0
  33. package/dist/modes/rpc/rpc-types.js.map +1 -1
  34. package/dist/modes/rpc/session-path-reservations.d.ts +30 -0
  35. package/dist/modes/rpc/session-path-reservations.d.ts.map +1 -0
  36. package/dist/modes/rpc/session-path-reservations.js +58 -0
  37. package/dist/modes/rpc/session-path-reservations.js.map +1 -0
  38. package/dist/modes/rpc/session-registry.d.ts +3 -1
  39. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  40. package/dist/modes/rpc/session-registry.js.map +1 -1
  41. package/dist/modes/rpc/session-worker-client.d.ts +10 -8
  42. package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
  43. package/dist/modes/rpc/session-worker-client.js +14 -23
  44. package/dist/modes/rpc/session-worker-client.js.map +1 -1
  45. package/dist/modes/rpc/session-worker-credit.d.ts +17 -0
  46. package/dist/modes/rpc/session-worker-credit.d.ts.map +1 -0
  47. package/dist/modes/rpc/session-worker-credit.js +39 -0
  48. package/dist/modes/rpc/session-worker-credit.js.map +1 -0
  49. package/dist/modes/rpc/session-worker-protocol.d.ts +10 -0
  50. package/dist/modes/rpc/session-worker-protocol.d.ts.map +1 -1
  51. package/dist/modes/rpc/session-worker-protocol.js +2 -0
  52. package/dist/modes/rpc/session-worker-protocol.js.map +1 -1
  53. package/dist/modes/rpc/session-worker-signals.d.ts +7 -0
  54. package/dist/modes/rpc/session-worker-signals.d.ts.map +1 -0
  55. package/dist/modes/rpc/session-worker-signals.js +19 -0
  56. package/dist/modes/rpc/session-worker-signals.js.map +1 -0
  57. package/dist/modes/rpc/session-worker.js +12 -16
  58. package/dist/modes/rpc/session-worker.js.map +1 -1
  59. package/dist/modes/rpc/worker-session-registry.d.ts +12 -0
  60. package/dist/modes/rpc/worker-session-registry.d.ts.map +1 -1
  61. package/dist/modes/rpc/worker-session-registry.js +51 -24
  62. package/dist/modes/rpc/worker-session-registry.js.map +1 -1
  63. package/docs/rpc.md +14 -6
  64. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
  65. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  66. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  67. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts +11 -0
  68. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts.map +1 -1
  69. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js +18 -0
  70. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js.map +1 -1
  71. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +1 -1
  72. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
  73. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +5 -1
  74. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
  75. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts +2 -0
  76. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts.map +1 -1
  77. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js +96 -51
  78. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js.map +1 -1
  79. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts +389 -1
  80. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts.map +1 -1
  81. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js +132 -4
  82. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js.map +1 -1
  83. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts +34 -4
  84. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts.map +1 -1
  85. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js +41 -8
  86. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js.map +1 -1
  87. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts +20 -0
  88. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts.map +1 -1
  89. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js +20 -0
  90. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js.map +1 -1
  91. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts +18 -6
  92. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts.map +1 -1
  93. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js +77 -35
  94. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js.map +1 -1
  95. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts +9 -3
  96. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts.map +1 -1
  97. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js +30 -38
  98. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js.map +1 -1
  99. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.d.ts +16 -0
  100. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.d.ts.map +1 -0
  101. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.js +69 -0
  102. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.js.map +1 -0
  103. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.d.ts +26 -0
  104. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.d.ts.map +1 -0
  105. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.js +61 -0
  106. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.js.map +1 -0
  107. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts +6 -4
  108. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts.map +1 -1
  109. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js +6 -4
  110. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js.map +1 -1
  111. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts +13 -5
  112. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts.map +1 -1
  113. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js +76 -21
  114. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js.map +1 -1
  115. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts +5 -0
  116. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts.map +1 -1
  117. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js +7 -2
  118. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js.map +1 -1
  119. package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.d.ts +32 -0
  120. package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.d.ts.map +1 -0
  121. package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.js +62 -0
  122. package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.js.map +1 -0
  123. package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.d.ts.map +1 -1
  124. package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.js +2 -1
  125. package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.js.map +1 -1
  126. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -1
  127. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  128. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -1
  129. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  130. package/node_modules/@earendil-works/pi-ai/dist/model.d.ts +11 -1
  131. package/node_modules/@earendil-works/pi-ai/dist/model.d.ts.map +1 -1
  132. package/node_modules/@earendil-works/pi-ai/dist/model.js.map +1 -1
  133. package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.d.ts.map +1 -1
  134. package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.js +2 -1
  135. package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.js.map +1 -1
  136. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  137. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  138. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  139. package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
  140. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  141. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts.map +1 -1
  142. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js +3 -3
  143. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js.map +1 -1
  144. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts +4 -2
  145. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts.map +1 -1
  146. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js +18 -9
  147. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js.map +1 -1
  148. package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.d.ts +12 -0
  149. package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.d.ts.map +1 -0
  150. package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.js +93 -0
  151. package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.js.map +1 -0
  152. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  153. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  154. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  155. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  156. package/package.json +7 -7
@@ -11,6 +11,26 @@
11
11
  export const DEVIN_DEFAULT_BASE_URL = "https://server.codeium.com";
12
12
  export const DEVIN_CHAT_MESSAGE_PATH = "/exa.api_server_pb.ApiServerService/GetChatMessage";
13
13
  export const DEVIN_CLI_MODEL_CONFIGS_PATH = "/exa.api_server_pb.ApiServerService/GetCliModelConfigs";
14
+ export const DEVIN_ASSIGN_MODEL_PATH = "/exa.api_server_pb.ApiServerService/AssignModel";
15
+ export const DEVIN_USER_JWT_PATH = "/exa.auth_pb.AuthService/GetUserJwt";
16
+ /**
17
+ * Request headers the released CLI sends on the streaming chat call. Auth rides
18
+ * inside `Metadata.api_key`, so there is no `authorization` header.
19
+ */
20
+ export const DEVIN_CHAT_HEADERS = {
21
+ "content-type": "application/connect+proto",
22
+ "connect-protocol-version": "1",
23
+ "connect-content-encoding": "gzip",
24
+ "accept-encoding": "identity",
25
+ "user-agent": "connect-go/1.18.1 (go1.26.3)",
26
+ "connect-accept-encoding": "gzip",
27
+ };
28
+ /** Unary Connect calls carry a bare protobuf body, not the 5-byte streaming frame. */
29
+ export const DEVIN_UNARY_HEADERS = {
30
+ "content-type": "application/proto",
31
+ "connect-protocol-version": "1",
32
+ accept: "*/*",
33
+ };
14
34
  /** Connect frame flags: bit 0 marks a gzipped payload, bit 1 the end-of-stream trailer. */
15
35
  export const DEVIN_COMPRESSED_FLAG = 0x01;
16
36
  export const DEVIN_TRAILER_FLAG = 0x02;
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/api/devin-agent/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,4BAA4B,CAAC;AACnE,MAAM,CAAC,MAAM,uBAAuB,GAAG,oDAAoD,CAAC;AAC5F,MAAM,CAAC,MAAM,4BAA4B,GAAG,wDAAwD,CAAC;AAErG,2FAA2F;AAC3F,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAC1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC","sourcesContent":["/**\n * Cascade RPC paths and wire constants.\n *\n * Devin's released CLI speaks the Connect protocol over HTTP/1.1 against\n * Codeium's Cascade edge. The service paths are spelled out here rather than\n * derived from a generated service descriptor: the vendored schema in\n * packages/ai/proto/devin/cascade.proto carries only the message subset the\n * transport needs, so its package name is cosmetic while these paths are the\n * real contract.\n */\n\nexport const DEVIN_DEFAULT_BASE_URL = \"https://server.codeium.com\";\nexport const DEVIN_CHAT_MESSAGE_PATH = \"/exa.api_server_pb.ApiServerService/GetChatMessage\";\nexport const DEVIN_CLI_MODEL_CONFIGS_PATH = \"/exa.api_server_pb.ApiServerService/GetCliModelConfigs\";\n\n/** Connect frame flags: bit 0 marks a gzipped payload, bit 1 the end-of-stream trailer. */\nexport const DEVIN_COMPRESSED_FLAG = 0x01;\nexport const DEVIN_TRAILER_FLAG = 0x02;\n\n/**\n * Hard upper bound on one Connect frame payload. The 4-byte length prefix can\n * describe 4 GiB; a corrupted or hostile prefix must not turn into an\n * allocation of that size, so anything larger is a protocol error.\n */\nexport const DEVIN_MAX_FRAME_PAYLOAD = 64 * 1024 * 1024;\n"]}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/api/devin-agent/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,4BAA4B,CAAC;AACnE,MAAM,CAAC,MAAM,uBAAuB,GAAG,oDAAoD,CAAC;AAC5F,MAAM,CAAC,MAAM,4BAA4B,GAAG,wDAAwD,CAAC;AACrG,MAAM,CAAC,MAAM,uBAAuB,GAAG,iDAAiD,CAAC;AACzF,MAAM,CAAC,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IACjC,cAAc,EAAE,2BAA2B;IAC3C,0BAA0B,EAAE,GAAG;IAC/B,0BAA0B,EAAE,MAAM;IAClC,iBAAiB,EAAE,UAAU;IAC7B,YAAY,EAAE,8BAA8B;IAC5C,yBAAyB,EAAE,MAAM;CACxB,CAAC;AAEX,sFAAsF;AACtF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAClC,cAAc,EAAE,mBAAmB;IACnC,0BAA0B,EAAE,GAAG;IAC/B,MAAM,EAAE,KAAK;CACJ,CAAC;AAEX,2FAA2F;AAC3F,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAC1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC","sourcesContent":["/**\n * Cascade RPC paths and wire constants.\n *\n * Devin's released CLI speaks the Connect protocol over HTTP/1.1 against\n * Codeium's Cascade edge. The service paths are spelled out here rather than\n * derived from a generated service descriptor: the vendored schema in\n * packages/ai/proto/devin/cascade.proto carries only the message subset the\n * transport needs, so its package name is cosmetic while these paths are the\n * real contract.\n */\n\nexport const DEVIN_DEFAULT_BASE_URL = \"https://server.codeium.com\";\nexport const DEVIN_CHAT_MESSAGE_PATH = \"/exa.api_server_pb.ApiServerService/GetChatMessage\";\nexport const DEVIN_CLI_MODEL_CONFIGS_PATH = \"/exa.api_server_pb.ApiServerService/GetCliModelConfigs\";\nexport const DEVIN_ASSIGN_MODEL_PATH = \"/exa.api_server_pb.ApiServerService/AssignModel\";\nexport const DEVIN_USER_JWT_PATH = \"/exa.auth_pb.AuthService/GetUserJwt\";\n\n/**\n * Request headers the released CLI sends on the streaming chat call. Auth rides\n * inside `Metadata.api_key`, so there is no `authorization` header.\n */\nexport const DEVIN_CHAT_HEADERS = {\n\t\"content-type\": \"application/connect+proto\",\n\t\"connect-protocol-version\": \"1\",\n\t\"connect-content-encoding\": \"gzip\",\n\t\"accept-encoding\": \"identity\",\n\t\"user-agent\": \"connect-go/1.18.1 (go1.26.3)\",\n\t\"connect-accept-encoding\": \"gzip\",\n} as const;\n\n/** Unary Connect calls carry a bare protobuf body, not the 5-byte streaming frame. */\nexport const DEVIN_UNARY_HEADERS = {\n\t\"content-type\": \"application/proto\",\n\t\"connect-protocol-version\": \"1\",\n\taccept: \"*/*\",\n} as const;\n\n/** Connect frame flags: bit 0 marks a gzipped payload, bit 1 the end-of-stream trailer. */\nexport const DEVIN_COMPRESSED_FLAG = 0x01;\nexport const DEVIN_TRAILER_FLAG = 0x02;\n\n/**\n * Hard upper bound on one Connect frame payload. The 4-byte length prefix can\n * describe 4 GiB; a corrupted or hostile prefix must not turn into an\n * allocation of that size, so anything larger is a protocol error.\n */\nexport const DEVIN_MAX_FRAME_PAYLOAD = 64 * 1024 * 1024;\n"]}
@@ -4,21 +4,33 @@
4
4
  *
5
5
  * Cascade has no system role: the system prompt travels in the top-level
6
6
  * `prompt` field, and history is a flat list of `ChatMessagePrompt` entries
7
- * whose `source` carries the role. Message ids are derived deterministically
8
- * from the conversation id and the entry index so a retried turn re-sends the
9
- * same ids instead of forking the server-side transcript.
7
+ * whose `source` carries the role. Message ids must be UUID-shaped; they are
8
+ * derived deterministically from the conversation id and the entry index so a
9
+ * retried turn re-sends the same ids instead of forking the server-side
10
+ * transcript, while a native Devin turn is replayed under the id the server
11
+ * minted for it.
10
12
  */
11
- import type { Context, Model } from "../../types.ts";
12
- import { type GetChatMessageRequest } from "./gen/cascade_pb.ts";
13
+ import type { Context, Message, Model } from "../../types.ts";
14
+ import { type ChatMessagePrompt, type GetChatMessageRequest } from "./gen/cascade_pb.ts";
13
15
  /** Cascade's own stop vocabulary; the server echoes these as STOP_PATTERN. */
14
16
  export declare const DEVIN_DEFAULT_STOP_PATTERNS: readonly ["<|user|>", "<|bot|>", "<|context_request|>", "<|endoftext|>", "<|end_of_turn|>"];
17
+ export interface DevinModelAssignment {
18
+ modelUid: string;
19
+ assignmentJwt: string;
20
+ }
15
21
  export interface DevinChatRequestInput {
16
22
  model: Model<"devin-agent">;
17
23
  context: Context;
18
24
  apiKey: string | undefined;
19
- cascadeId?: string;
25
+ userJwt?: string;
26
+ cascadeId: string;
27
+ assignment?: DevinModelAssignment;
20
28
  maxTokens?: number;
21
29
  temperature?: number;
30
+ topP?: number;
31
+ stopSequences?: readonly string[];
22
32
  }
23
33
  export declare function buildDevinChatRequest(input: DevinChatRequestInput): GetChatMessageRequest;
34
+ /** The router scores the latest user turn alone; the chat request mints the turn's id. */
35
+ export declare function buildDevinRouterPrompt(messages: readonly Message[]): ChatMessagePrompt | undefined;
24
36
  //# sourceMappingURL=request.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/request.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAW,KAAK,EAAQ,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAUN,KAAK,qBAAqB,EAG1B,MAAM,qBAAqB,CAAC;AAG7B,8EAA8E;AAC9E,eAAO,MAAM,2BAA2B,YACvC,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,eAAe,EACf,iBAAiB,CACR,CAAC;AAEX,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,qBAAqB,CAoBzF"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/request.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAQ,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAEN,KAAK,iBAAiB,EAQtB,KAAK,qBAAqB,EAK1B,MAAM,qBAAqB,CAAC;AAG7B,8EAA8E;AAC9E,eAAO,MAAM,2BAA2B,YACvC,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,eAAe,EACf,iBAAiB,CACR,CAAC;AAOX,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,qBAAqB,CA6BzF;AAED,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,iBAAiB,GAAG,SAAS,CAMlG"}
@@ -4,12 +4,15 @@
4
4
  *
5
5
  * Cascade has no system role: the system prompt travels in the top-level
6
6
  * `prompt` field, and history is a flat list of `ChatMessagePrompt` entries
7
- * whose `source` carries the role. Message ids are derived deterministically
8
- * from the conversation id and the entry index so a retried turn re-sends the
9
- * same ids instead of forking the server-side transcript.
7
+ * whose `source` carries the role. Message ids must be UUID-shaped; they are
8
+ * derived deterministically from the conversation id and the entry index so a
9
+ * retried turn re-sends the same ids instead of forking the server-side
10
+ * transcript, while a native Devin turn is replayed under the id the server
11
+ * minted for it.
10
12
  */
11
13
  import { create } from "@bufbuild/protobuf";
12
- import { CacheControlType, ChatMessagePromptSchema, ChatMessageRequestType, ChatMessageSource, ChatToolCallSchema, ChatToolDefinitionSchema, CompletionConfigurationSchema, ConversationalPlannerMode, GetChatMessageRequestSchema, PromptCacheOptionsSchema, } from "./gen/cascade_pb.js";
14
+ import { deterministicUuid } from "../cursor-agent/deterministic-id.js";
15
+ import { CacheControlType, ChatMessagePromptSchema, ChatMessageRequestType, ChatMessageSource, ChatToolCallSchema, ChatToolDefinitionSchema, CompletionConfigurationSchema, ConversationalPlannerMode, GetChatMessageRequestSchema, ImageDataSchema, PromptCacheOptionsSchema, } from "./gen/cascade_pb.js";
13
16
  import { devinCliMetadata } from "./metadata.js";
14
17
  /** Cascade's own stop vocabulary; the server echoes these as STOP_PATTERN. */
15
18
  export const DEVIN_DEFAULT_STOP_PATTERNS = [
@@ -19,66 +22,95 @@ export const DEVIN_DEFAULT_STOP_PATTERNS = [
19
22
  "<|endoftext|>",
20
23
  "<|end_of_turn|>",
21
24
  ];
25
+ const DEFAULT_MAX_TOKENS = 64_000;
26
+ const DEFAULT_TEMPERATURE = 0.4;
27
+ /** Cascade refuses a temperature of exactly 0 (proto3 drops it) with an opaque invalid_argument. */
28
+ const MIN_TEMPERATURE = 0.0001;
22
29
  export function buildDevinChatRequest(input) {
23
- const cascadeId = input.cascadeId ?? "";
30
+ const temperature = Math.max(input.temperature ?? DEFAULT_TEMPERATURE, MIN_TEMPERATURE);
31
+ const stopPatterns = [...DEVIN_DEFAULT_STOP_PATTERNS, ...(input.stopSequences ?? [])];
24
32
  return create(GetChatMessageRequestSchema, {
25
- metadata: devinCliMetadata(input.apiKey),
33
+ metadata: devinCliMetadata(input.apiKey, input.userJwt ?? ""),
26
34
  prompt: input.context.systemPrompt ?? "",
27
- chatMessagePrompts: mapHistory(input.context.messages, cascadeId),
35
+ chatMessagePrompts: mapHistory(input.context.messages, input.cascadeId, input.model),
28
36
  requestType: ChatMessageRequestType.CASCADE,
29
37
  plannerMode: ConversationalPlannerMode.DEFAULT,
30
- chatModelUid: input.model.id,
31
- chatModelName: input.model.name ?? input.model.id,
32
- cascadeId,
38
+ chatModelUid: input.assignment?.modelUid ?? input.model.upstreamModelId ?? input.model.id,
39
+ ...(input.assignment ? { modelAssignmentJwt: input.assignment.assignmentJwt } : {}),
40
+ cascadeId: input.cascadeId,
41
+ executionId: crypto.randomUUID(),
33
42
  tools: (input.context.tools ?? []).map(toolDefinition),
34
43
  toolChoice: { choice: { case: "optionName", value: "auto" } },
35
44
  systemPromptCacheOptions: create(PromptCacheOptionsSchema, { type: CacheControlType.EPHEMERAL }),
45
+ disableParallelToolCalls: input.model.compat?.supportsParallelToolCalls !== true,
36
46
  configuration: create(CompletionConfigurationSchema, {
37
- maxTokens: BigInt(input.maxTokens ?? input.model.maxTokens ?? 0),
38
- temperature: input.temperature ?? 0,
39
- stopPatterns: [...DEVIN_DEFAULT_STOP_PATTERNS],
47
+ numCompletions: 1n,
48
+ maxTokens: BigInt(input.maxTokens ?? input.model.maxTokens ?? DEFAULT_MAX_TOKENS),
49
+ maxNewlines: 200n,
50
+ temperature,
51
+ firstTemperature: temperature,
52
+ topK: 50n,
53
+ topP: input.topP ?? 1,
54
+ stopPatterns,
55
+ fimEotProbThreshold: 1,
40
56
  }),
41
57
  });
42
58
  }
59
+ /** The router scores the latest user turn alone; the chat request mints the turn's id. */
60
+ export function buildDevinRouterPrompt(messages) {
61
+ for (let index = messages.length - 1; index >= 0; index--) {
62
+ const message = messages[index];
63
+ if (message?.role === "user")
64
+ return userPrompt(message, "");
65
+ }
66
+ return undefined;
67
+ }
43
68
  function toolDefinition(tool) {
44
69
  return create(ChatToolDefinitionSchema, {
45
70
  name: tool.name,
46
71
  description: tool.description,
47
72
  jsonSchemaString: JSON.stringify(tool.parameters ?? {}),
73
+ strict: false,
48
74
  });
49
75
  }
50
- function mapHistory(messages, cascadeId) {
76
+ function mapHistory(messages, cascadeId, model) {
51
77
  const prompts = [];
52
78
  for (const [index, message] of messages.entries()) {
53
- const id = `${cascadeId}\u0000${index}\u0000${message.role}`;
79
+ const seed = `${cascadeId}\u0000${index}\u0000${message.role}`;
54
80
  if (message.role === "user")
55
- prompts.push(userPrompt(message.content, id));
56
- else if (message.role === "assistant")
57
- prompts.push(assistantPrompt(message, id));
58
- else if (message.role === "toolResult")
59
- prompts.push(toolResultPrompt(message, id));
81
+ prompts.push(userPrompt(message, deterministicUuid(seed)));
82
+ else if (message.role === "assistant") {
83
+ const prompt = assistantPrompt(message, model, `bot-${deterministicUuid(seed)}`);
84
+ if (prompt)
85
+ prompts.push(prompt);
86
+ }
87
+ else if (message.role === "toolResult") {
88
+ prompts.push(toolResultPrompt(message, deterministicUuid(`${seed}\u0000${message.toolCallId}`)));
89
+ }
60
90
  }
61
91
  return prompts;
62
92
  }
63
- function userPrompt(content, messageId) {
64
- const text = typeof content === "string" ? content : joinText(content);
93
+ function userPrompt(message, messageId) {
94
+ const { text, images } = splitContent(typeof message.content === "string" ? [] : message.content);
65
95
  return create(ChatMessagePromptSchema, {
66
96
  messageId,
67
97
  source: ChatMessageSource.USER,
68
- prompt: text,
98
+ prompt: typeof message.content === "string" ? message.content : text,
99
+ images,
69
100
  });
70
101
  }
71
- function assistantPrompt(message, messageId) {
72
- const text = [];
102
+ function assistantPrompt(message, model, fallbackId) {
103
+ const native = message.api === model.api && message.provider === model.provider && message.model === model.id;
104
+ let text = "";
73
105
  let thinking = "";
74
106
  let signature = "";
75
107
  const toolCalls = [];
76
108
  for (const block of message.content) {
77
109
  if (block.type === "text")
78
- text.push(block.text);
110
+ text += block.text;
79
111
  else if (block.type === "thinking") {
80
112
  thinking += block.thinking;
81
- if (block.thinkingSignature)
113
+ if (native && !signature && block.thinkingSignature)
82
114
  signature = block.thinkingSignature;
83
115
  }
84
116
  else if (block.type === "toolCall") {
@@ -89,28 +121,38 @@ function assistantPrompt(message, messageId) {
89
121
  }));
90
122
  }
91
123
  }
124
+ if (!text && !thinking && !signature && toolCalls.length === 0)
125
+ return undefined;
92
126
  return create(ChatMessagePromptSchema, {
93
- messageId,
127
+ messageId: native && message.responseId ? message.responseId : fallbackId,
94
128
  source: ChatMessageSource.SYSTEM,
95
- prompt: text.join("\n"),
129
+ prompt: text,
96
130
  thinking,
97
131
  signature,
132
+ signatureType: "",
98
133
  toolCalls,
99
134
  });
100
135
  }
101
136
  function toolResultPrompt(message, messageId) {
137
+ const { text, images } = splitContent(message.content);
102
138
  return create(ChatMessagePromptSchema, {
103
139
  messageId,
104
140
  source: ChatMessageSource.TOOL,
105
- prompt: joinText(message.content),
141
+ prompt: text,
142
+ images,
106
143
  toolCallId: message.toolCallId,
107
144
  toolResultIsError: message.isError === true,
108
145
  });
109
146
  }
110
- function joinText(content) {
111
- return content
112
- .filter((block) => block.type === "text" && typeof block.text === "string")
113
- .map((block) => block.text)
114
- .join("\n");
147
+ function splitContent(content) {
148
+ let text = "";
149
+ const images = [];
150
+ for (const block of content) {
151
+ if (block.type === "text")
152
+ text += block.text;
153
+ else
154
+ images.push(create(ImageDataSchema, { base64Data: block.data, mimeType: block.mimeType }));
155
+ }
156
+ return { text, images };
115
157
  }
116
158
  //# sourceMappingURL=request.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/api/devin-agent/request.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Builds the Cascade `GetChatMessage` request from senpi's provider-neutral\n * context.\n *\n * Cascade has no system role: the system prompt travels in the top-level\n * `prompt` field, and history is a flat list of `ChatMessagePrompt` entries\n * whose `source` carries the role. Message ids are derived deterministically\n * from the conversation id and the entry index so a retried turn re-sends the\n * same ids instead of forking the server-side transcript.\n */\n\nimport { create } from \"@bufbuild/protobuf\";\nimport type { Context, Message, Model, Tool } from \"../../types.ts\";\nimport {\n\tCacheControlType,\n\ttype ChatMessagePrompt,\n\tChatMessagePromptSchema,\n\tChatMessageRequestType,\n\tChatMessageSource,\n\tChatToolCallSchema,\n\tChatToolDefinitionSchema,\n\tCompletionConfigurationSchema,\n\tConversationalPlannerMode,\n\ttype GetChatMessageRequest,\n\tGetChatMessageRequestSchema,\n\tPromptCacheOptionsSchema,\n} from \"./gen/cascade_pb.ts\";\nimport { devinCliMetadata } from \"./metadata.ts\";\n\n/** Cascade's own stop vocabulary; the server echoes these as STOP_PATTERN. */\nexport const DEVIN_DEFAULT_STOP_PATTERNS = [\n\t\"<|user|>\",\n\t\"<|bot|>\",\n\t\"<|context_request|>\",\n\t\"<|endoftext|>\",\n\t\"<|end_of_turn|>\",\n] as const;\n\nexport interface DevinChatRequestInput {\n\tmodel: Model<\"devin-agent\">;\n\tcontext: Context;\n\tapiKey: string | undefined;\n\tcascadeId?: string;\n\tmaxTokens?: number;\n\ttemperature?: number;\n}\n\nexport function buildDevinChatRequest(input: DevinChatRequestInput): GetChatMessageRequest {\n\tconst cascadeId = input.cascadeId ?? \"\";\n\treturn create(GetChatMessageRequestSchema, {\n\t\tmetadata: devinCliMetadata(input.apiKey),\n\t\tprompt: input.context.systemPrompt ?? \"\",\n\t\tchatMessagePrompts: mapHistory(input.context.messages, cascadeId),\n\t\trequestType: ChatMessageRequestType.CASCADE,\n\t\tplannerMode: ConversationalPlannerMode.DEFAULT,\n\t\tchatModelUid: input.model.id,\n\t\tchatModelName: input.model.name ?? input.model.id,\n\t\tcascadeId,\n\t\ttools: (input.context.tools ?? []).map(toolDefinition),\n\t\ttoolChoice: { choice: { case: \"optionName\", value: \"auto\" } },\n\t\tsystemPromptCacheOptions: create(PromptCacheOptionsSchema, { type: CacheControlType.EPHEMERAL }),\n\t\tconfiguration: create(CompletionConfigurationSchema, {\n\t\t\tmaxTokens: BigInt(input.maxTokens ?? input.model.maxTokens ?? 0),\n\t\t\ttemperature: input.temperature ?? 0,\n\t\t\tstopPatterns: [...DEVIN_DEFAULT_STOP_PATTERNS],\n\t\t}),\n\t});\n}\n\nfunction toolDefinition(tool: Tool) {\n\treturn create(ChatToolDefinitionSchema, {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tjsonSchemaString: JSON.stringify(tool.parameters ?? {}),\n\t});\n}\n\nfunction mapHistory(messages: readonly Message[], cascadeId: string): ChatMessagePrompt[] {\n\tconst prompts: ChatMessagePrompt[] = [];\n\tfor (const [index, message] of messages.entries()) {\n\t\tconst id = `${cascadeId}\\u0000${index}\\u0000${message.role}`;\n\t\tif (message.role === \"user\") prompts.push(userPrompt(message.content, id));\n\t\telse if (message.role === \"assistant\") prompts.push(assistantPrompt(message, id));\n\t\telse if (message.role === \"toolResult\") prompts.push(toolResultPrompt(message, id));\n\t}\n\treturn prompts;\n}\n\nfunction userPrompt(content: Extract<Message, { role: \"user\" }>[\"content\"], messageId: string): ChatMessagePrompt {\n\tconst text = typeof content === \"string\" ? content : joinText(content);\n\treturn create(ChatMessagePromptSchema, {\n\t\tmessageId,\n\t\tsource: ChatMessageSource.USER,\n\t\tprompt: text,\n\t});\n}\n\nfunction assistantPrompt(message: Extract<Message, { role: \"assistant\" }>, messageId: string): ChatMessagePrompt {\n\tconst text: string[] = [];\n\tlet thinking = \"\";\n\tlet signature = \"\";\n\tconst toolCalls = [];\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") text.push(block.text);\n\t\telse if (block.type === \"thinking\") {\n\t\t\tthinking += block.thinking;\n\t\t\tif (block.thinkingSignature) signature = block.thinkingSignature;\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\ttoolCalls.push(\n\t\t\t\tcreate(ChatToolCallSchema, {\n\t\t\t\t\tid: block.id,\n\t\t\t\t\tname: block.name,\n\t\t\t\t\targumentsJson: JSON.stringify(block.arguments ?? {}),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\treturn create(ChatMessagePromptSchema, {\n\t\tmessageId,\n\t\tsource: ChatMessageSource.SYSTEM,\n\t\tprompt: text.join(\"\\n\"),\n\t\tthinking,\n\t\tsignature,\n\t\ttoolCalls,\n\t});\n}\n\nfunction toolResultPrompt(message: Extract<Message, { role: \"toolResult\" }>, messageId: string): ChatMessagePrompt {\n\treturn create(ChatMessagePromptSchema, {\n\t\tmessageId,\n\t\tsource: ChatMessageSource.TOOL,\n\t\tprompt: joinText(message.content),\n\t\ttoolCallId: message.toolCallId,\n\t\ttoolResultIsError: message.isError === true,\n\t});\n}\n\nfunction joinText(content: readonly { type: string; text?: string }[]): string {\n\treturn content\n\t\t.filter((block) => block.type === \"text\" && typeof block.text === \"string\")\n\t\t.map((block) => block.text as string)\n\t\t.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/api/devin-agent/request.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Builds the Cascade `GetChatMessage` request from senpi's provider-neutral\n * context.\n *\n * Cascade has no system role: the system prompt travels in the top-level\n * `prompt` field, and history is a flat list of `ChatMessagePrompt` entries\n * whose `source` carries the role. Message ids must be UUID-shaped; they are\n * derived deterministically from the conversation id and the entry index so a\n * retried turn re-sends the same ids instead of forking the server-side\n * transcript, while a native Devin turn is replayed under the id the server\n * minted for it.\n */\n\nimport { create } from \"@bufbuild/protobuf\";\nimport type { Context, Message, Model, Tool } from \"../../types.ts\";\nimport { deterministicUuid } from \"../cursor-agent/deterministic-id.ts\";\nimport {\n\tCacheControlType,\n\ttype ChatMessagePrompt,\n\tChatMessagePromptSchema,\n\tChatMessageRequestType,\n\tChatMessageSource,\n\tChatToolCallSchema,\n\tChatToolDefinitionSchema,\n\tCompletionConfigurationSchema,\n\tConversationalPlannerMode,\n\ttype GetChatMessageRequest,\n\tGetChatMessageRequestSchema,\n\ttype ImageData,\n\tImageDataSchema,\n\tPromptCacheOptionsSchema,\n} from \"./gen/cascade_pb.ts\";\nimport { devinCliMetadata } from \"./metadata.ts\";\n\n/** Cascade's own stop vocabulary; the server echoes these as STOP_PATTERN. */\nexport const DEVIN_DEFAULT_STOP_PATTERNS = [\n\t\"<|user|>\",\n\t\"<|bot|>\",\n\t\"<|context_request|>\",\n\t\"<|endoftext|>\",\n\t\"<|end_of_turn|>\",\n] as const;\n\nconst DEFAULT_MAX_TOKENS = 64_000;\nconst DEFAULT_TEMPERATURE = 0.4;\n/** Cascade refuses a temperature of exactly 0 (proto3 drops it) with an opaque invalid_argument. */\nconst MIN_TEMPERATURE = 0.0001;\n\nexport interface DevinModelAssignment {\n\tmodelUid: string;\n\tassignmentJwt: string;\n}\n\nexport interface DevinChatRequestInput {\n\tmodel: Model<\"devin-agent\">;\n\tcontext: Context;\n\tapiKey: string | undefined;\n\tuserJwt?: string;\n\tcascadeId: string;\n\tassignment?: DevinModelAssignment;\n\tmaxTokens?: number;\n\ttemperature?: number;\n\ttopP?: number;\n\tstopSequences?: readonly string[];\n}\n\ntype UserMessage = Extract<Message, { role: \"user\" }>;\ntype AssistantMessage = Extract<Message, { role: \"assistant\" }>;\ntype ToolResultMessage = Extract<Message, { role: \"toolResult\" }>;\n\nexport function buildDevinChatRequest(input: DevinChatRequestInput): GetChatMessageRequest {\n\tconst temperature = Math.max(input.temperature ?? DEFAULT_TEMPERATURE, MIN_TEMPERATURE);\n\tconst stopPatterns = [...DEVIN_DEFAULT_STOP_PATTERNS, ...(input.stopSequences ?? [])];\n\treturn create(GetChatMessageRequestSchema, {\n\t\tmetadata: devinCliMetadata(input.apiKey, input.userJwt ?? \"\"),\n\t\tprompt: input.context.systemPrompt ?? \"\",\n\t\tchatMessagePrompts: mapHistory(input.context.messages, input.cascadeId, input.model),\n\t\trequestType: ChatMessageRequestType.CASCADE,\n\t\tplannerMode: ConversationalPlannerMode.DEFAULT,\n\t\tchatModelUid: input.assignment?.modelUid ?? input.model.upstreamModelId ?? input.model.id,\n\t\t...(input.assignment ? { modelAssignmentJwt: input.assignment.assignmentJwt } : {}),\n\t\tcascadeId: input.cascadeId,\n\t\texecutionId: crypto.randomUUID(),\n\t\ttools: (input.context.tools ?? []).map(toolDefinition),\n\t\ttoolChoice: { choice: { case: \"optionName\", value: \"auto\" } },\n\t\tsystemPromptCacheOptions: create(PromptCacheOptionsSchema, { type: CacheControlType.EPHEMERAL }),\n\t\tdisableParallelToolCalls: input.model.compat?.supportsParallelToolCalls !== true,\n\t\tconfiguration: create(CompletionConfigurationSchema, {\n\t\t\tnumCompletions: 1n,\n\t\t\tmaxTokens: BigInt(input.maxTokens ?? input.model.maxTokens ?? DEFAULT_MAX_TOKENS),\n\t\t\tmaxNewlines: 200n,\n\t\t\ttemperature,\n\t\t\tfirstTemperature: temperature,\n\t\t\ttopK: 50n,\n\t\t\ttopP: input.topP ?? 1,\n\t\t\tstopPatterns,\n\t\t\tfimEotProbThreshold: 1,\n\t\t}),\n\t});\n}\n\n/** The router scores the latest user turn alone; the chat request mints the turn's id. */\nexport function buildDevinRouterPrompt(messages: readonly Message[]): ChatMessagePrompt | undefined {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst message = messages[index];\n\t\tif (message?.role === \"user\") return userPrompt(message, \"\");\n\t}\n\treturn undefined;\n}\n\nfunction toolDefinition(tool: Tool) {\n\treturn create(ChatToolDefinitionSchema, {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tjsonSchemaString: JSON.stringify(tool.parameters ?? {}),\n\t\tstrict: false,\n\t});\n}\n\nfunction mapHistory(messages: readonly Message[], cascadeId: string, model: Model<\"devin-agent\">): ChatMessagePrompt[] {\n\tconst prompts: ChatMessagePrompt[] = [];\n\tfor (const [index, message] of messages.entries()) {\n\t\tconst seed = `${cascadeId}\\u0000${index}\\u0000${message.role}`;\n\t\tif (message.role === \"user\") prompts.push(userPrompt(message, deterministicUuid(seed)));\n\t\telse if (message.role === \"assistant\") {\n\t\t\tconst prompt = assistantPrompt(message, model, `bot-${deterministicUuid(seed)}`);\n\t\t\tif (prompt) prompts.push(prompt);\n\t\t} else if (message.role === \"toolResult\") {\n\t\t\tprompts.push(toolResultPrompt(message, deterministicUuid(`${seed}\\u0000${message.toolCallId}`)));\n\t\t}\n\t}\n\treturn prompts;\n}\n\nfunction userPrompt(message: UserMessage, messageId: string): ChatMessagePrompt {\n\tconst { text, images } = splitContent(typeof message.content === \"string\" ? [] : message.content);\n\treturn create(ChatMessagePromptSchema, {\n\t\tmessageId,\n\t\tsource: ChatMessageSource.USER,\n\t\tprompt: typeof message.content === \"string\" ? message.content : text,\n\t\timages,\n\t});\n}\n\nfunction assistantPrompt(\n\tmessage: AssistantMessage,\n\tmodel: Model<\"devin-agent\">,\n\tfallbackId: string,\n): ChatMessagePrompt | undefined {\n\tconst native = message.api === model.api && message.provider === model.provider && message.model === model.id;\n\tlet text = \"\";\n\tlet thinking = \"\";\n\tlet signature = \"\";\n\tconst toolCalls = [];\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") text += block.text;\n\t\telse if (block.type === \"thinking\") {\n\t\t\tthinking += block.thinking;\n\t\t\tif (native && !signature && block.thinkingSignature) signature = block.thinkingSignature;\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\ttoolCalls.push(\n\t\t\t\tcreate(ChatToolCallSchema, {\n\t\t\t\t\tid: block.id,\n\t\t\t\t\tname: block.name,\n\t\t\t\t\targumentsJson: JSON.stringify(block.arguments ?? {}),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\tif (!text && !thinking && !signature && toolCalls.length === 0) return undefined;\n\treturn create(ChatMessagePromptSchema, {\n\t\tmessageId: native && message.responseId ? message.responseId : fallbackId,\n\t\tsource: ChatMessageSource.SYSTEM,\n\t\tprompt: text,\n\t\tthinking,\n\t\tsignature,\n\t\tsignatureType: \"\",\n\t\ttoolCalls,\n\t});\n}\n\nfunction toolResultPrompt(message: ToolResultMessage, messageId: string): ChatMessagePrompt {\n\tconst { text, images } = splitContent(message.content);\n\treturn create(ChatMessagePromptSchema, {\n\t\tmessageId,\n\t\tsource: ChatMessageSource.TOOL,\n\t\tprompt: text,\n\t\timages,\n\t\ttoolCallId: message.toolCallId,\n\t\ttoolResultIsError: message.isError === true,\n\t});\n}\n\nfunction splitContent(\n\tcontent: readonly ({ type: \"text\"; text: string } | { type: \"image\"; data: string; mimeType: string })[],\n): { text: string; images: ImageData[] } {\n\tlet text = \"\";\n\tconst images: ImageData[] = [];\n\tfor (const block of content) {\n\t\tif (block.type === \"text\") text += block.text;\n\t\telse images.push(create(ImageDataSchema, { base64Data: block.data, mimeType: block.mimeType }));\n\t}\n\treturn { text, images };\n}\n"]}
@@ -9,12 +9,18 @@
9
9
  import type { AssistantMessage } from "../../types.ts";
10
10
  import type { AssistantMessageEventStream } from "../../utils/event-stream.ts";
11
11
  import { type GetChatMessageResponse } from "./gen/cascade_pb.ts";
12
+ export interface DevinToolCallState {
13
+ contentIndex: number;
14
+ /** Raw JSON accumulated across chunks; the content block holds the parsed view. */
15
+ argumentsJson: string;
16
+ }
12
17
  export interface DevinStreamState {
13
18
  textIndex: number | undefined;
14
19
  thinkingIndex: number | undefined;
15
- toolCalls: Map<string, {
16
- contentIndex: number;
17
- }>;
20
+ toolCalls: Map<string, DevinToolCallState>;
21
+ /** Chunks after the first arrive without an id; they belong to this call. */
22
+ activeToolCallId: string | undefined;
18
23
  }
24
+ export declare function createDevinStreamState(): DevinStreamState;
19
25
  export declare function applyDevinResponse(message: GetChatMessageResponse, output: AssistantMessage, events: AssistantMessageEventStream, state: DevinStreamState): void;
20
26
  //# sourceMappingURL=stream-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-state.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/stream-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAY,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,KAAK,sBAAsB,EAAc,MAAM,qBAAqB,CAAC;AAE9E,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,gBAAgB,GACrB,IAAI,CASN"}
1
+ {"version":3,"file":"stream-state.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/stream-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAY,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAE/E,OAAO,EAAE,KAAK,sBAAsB,EAAc,MAAM,qBAAqB,CAAC;AAE9E,MAAM,WAAW,kBAAkB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC3C,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,gBAAgB,GACrB,IAAI,CASN"}
@@ -6,7 +6,11 @@
6
6
  * or closes them. This module owns the open-block state so the adapter emits
7
7
  * senpi's start/delta/end triples in the right order.
8
8
  */
9
+ import { parseStreamingJson } from "../../utils/json-parse.js";
9
10
  import { StopReason } from "./gen/cascade_pb.js";
11
+ export function createDevinStreamState() {
12
+ return { textIndex: undefined, thinkingIndex: undefined, toolCalls: new Map(), activeToolCallId: undefined };
13
+ }
10
14
  export function applyDevinResponse(message, output, events, state) {
11
15
  if (message.messageId && !output.responseId)
12
16
  output.responseId = message.messageId;
@@ -65,33 +69,34 @@ function appendToolCall(call, output, events, state) {
65
69
  closeText(output, events, state);
66
70
  if (state.thinkingIndex !== undefined)
67
71
  closeThinking(output, events, state);
68
- const existing = state.toolCalls.get(call.id);
69
- if (existing !== undefined) {
70
- const open = output.content[existing.contentIndex];
71
- if (open?.type === "toolCall" && call.argumentsJson) {
72
- open.arguments = parseArguments(call.argumentsJson, open.arguments);
73
- events.push({
74
- type: "toolcall_delta",
75
- contentIndex: existing.contentIndex,
76
- delta: call.argumentsJson,
77
- partial: output,
78
- });
79
- }
72
+ const toolCallId = call.id || state.activeToolCallId;
73
+ if (!toolCallId)
80
74
  return;
75
+ state.activeToolCallId = toolCallId;
76
+ let entry = state.toolCalls.get(toolCallId);
77
+ if (entry === undefined) {
78
+ const block = { type: "toolCall", id: toolCallId, name: call.name, arguments: {} };
79
+ output.content.push(block);
80
+ entry = { contentIndex: output.content.length - 1, argumentsJson: "" };
81
+ state.toolCalls.set(toolCallId, entry);
82
+ events.push({ type: "toolcall_start", contentIndex: entry.contentIndex, partial: output });
81
83
  }
82
- const block = {
83
- type: "toolCall",
84
- id: call.id,
85
- name: call.name,
86
- arguments: parseArguments(call.argumentsJson, {}),
87
- };
88
- output.content.push(block);
89
- const contentIndex = output.content.length - 1;
90
- state.toolCalls.set(call.id, { contentIndex });
91
- events.push({ type: "toolcall_start", contentIndex, partial: output });
92
- if (call.argumentsJson) {
93
- events.push({ type: "toolcall_delta", contentIndex, delta: call.argumentsJson, partial: output });
94
- }
84
+ const block = output.content[entry.contentIndex];
85
+ if (block?.type !== "toolCall")
86
+ return;
87
+ if (call.name)
88
+ block.name = call.name;
89
+ if (!call.argumentsJson)
90
+ return;
91
+ // A chunk either repeats everything so far plus new bytes, or carries only the new bytes.
92
+ const accumulated = call.argumentsJson.startsWith(entry.argumentsJson)
93
+ ? call.argumentsJson
94
+ : entry.argumentsJson + call.argumentsJson;
95
+ const delta = accumulated.slice(entry.argumentsJson.length);
96
+ entry.argumentsJson = accumulated;
97
+ block.arguments = parseStreamingJson(accumulated);
98
+ if (delta)
99
+ events.push({ type: "toolcall_delta", contentIndex: entry.contentIndex, delta, partial: output });
95
100
  }
96
101
  function closeText(output, events, state) {
97
102
  const index = state.textIndex;
@@ -137,17 +142,4 @@ function mapStopReason(reason) {
137
142
  return "stop";
138
143
  }
139
144
  }
140
- function parseArguments(json, fallback) {
141
- if (!json)
142
- return fallback;
143
- try {
144
- const parsed = JSON.parse(json);
145
- return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
146
- ? parsed
147
- : fallback;
148
- }
149
- catch {
150
- return fallback;
151
- }
152
- }
153
145
  //# sourceMappingURL=stream-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-state.js","sourceRoot":"","sources":["../../../src/api/devin-agent/stream-state.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Cascade delta bookkeeping.\n *\n * One Cascade response frame can carry a thinking delta, a text delta and a\n * finished tool call at once, and blocks are implicit: the server never opens\n * or closes them. This module owns the open-block state so the adapter emits\n * senpi's start/delta/end triples in the right order.\n */\n\nimport type { AssistantMessage, ToolCall } from \"../../types.ts\";\nimport type { AssistantMessageEventStream } from \"../../utils/event-stream.ts\";\nimport { type GetChatMessageResponse, StopReason } from \"./gen/cascade_pb.ts\";\n\nexport interface DevinStreamState {\n\ttextIndex: number | undefined;\n\tthinkingIndex: number | undefined;\n\ttoolCalls: Map<string, { contentIndex: number }>;\n}\n\nexport function applyDevinResponse(\n\tmessage: GetChatMessageResponse,\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\tif (message.messageId && !output.responseId) output.responseId = message.messageId;\n\tif (message.actualModelUid) output.responseModel = message.actualModelUid;\n\n\tif (message.deltaThinking) appendThinking(message, output, events, state);\n\tif (message.deltaText) appendText(message.deltaText, output, events, state);\n\tfor (const call of message.deltaToolCalls) appendToolCall(call, output, events, state);\n\tif (message.usage) applyUsage(message, output);\n\tif (message.stopReason !== StopReason.UNSPECIFIED) output.stopReason = mapStopReason(message.stopReason);\n}\n\nfunction appendThinking(\n\tmessage: GetChatMessageResponse,\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\t// A thinking block interleaved after text starts a new block, matching the\n\t// order Cascade streamed it in.\n\tif (state.textIndex !== undefined) closeText(output, events, state);\n\tif (state.thinkingIndex === undefined) {\n\t\toutput.content.push({ type: \"thinking\", thinking: \"\", ...(message.thinkingRedacted ? { redacted: true } : {}) });\n\t\tstate.thinkingIndex = output.content.length - 1;\n\t\tevents.push({ type: \"thinking_start\", contentIndex: state.thinkingIndex, partial: output });\n\t}\n\tconst block = output.content[state.thinkingIndex];\n\tif (block?.type !== \"thinking\") return;\n\tblock.thinking += message.deltaThinking;\n\tif (message.deltaSignature) block.thinkingSignature = message.deltaSignature;\n\tevents.push({\n\t\ttype: \"thinking_delta\",\n\t\tcontentIndex: state.thinkingIndex,\n\t\tdelta: message.deltaThinking,\n\t\tpartial: output,\n\t});\n}\n\nfunction appendText(\n\tdelta: string,\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\tif (state.thinkingIndex !== undefined) closeThinking(output, events, state);\n\tif (state.textIndex === undefined) {\n\t\toutput.content.push({ type: \"text\", text: \"\" });\n\t\tstate.textIndex = output.content.length - 1;\n\t\tevents.push({ type: \"text_start\", contentIndex: state.textIndex, partial: output });\n\t}\n\tconst block = output.content[state.textIndex];\n\tif (block?.type !== \"text\") return;\n\tblock.text += delta;\n\tevents.push({ type: \"text_delta\", contentIndex: state.textIndex, delta, partial: output });\n}\n\nfunction appendToolCall(\n\tcall: { id: string; name: string; argumentsJson: string },\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\tif (state.textIndex !== undefined) closeText(output, events, state);\n\tif (state.thinkingIndex !== undefined) closeThinking(output, events, state);\n\tconst existing = state.toolCalls.get(call.id);\n\tif (existing !== undefined) {\n\t\tconst open = output.content[existing.contentIndex];\n\t\tif (open?.type === \"toolCall\" && call.argumentsJson) {\n\t\t\topen.arguments = parseArguments(call.argumentsJson, open.arguments);\n\t\t\tevents.push({\n\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\tcontentIndex: existing.contentIndex,\n\t\t\t\tdelta: call.argumentsJson,\n\t\t\t\tpartial: output,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\tconst block: ToolCall = {\n\t\ttype: \"toolCall\",\n\t\tid: call.id,\n\t\tname: call.name,\n\t\targuments: parseArguments(call.argumentsJson, {}),\n\t};\n\toutput.content.push(block);\n\tconst contentIndex = output.content.length - 1;\n\tstate.toolCalls.set(call.id, { contentIndex });\n\tevents.push({ type: \"toolcall_start\", contentIndex, partial: output });\n\tif (call.argumentsJson) {\n\t\tevents.push({ type: \"toolcall_delta\", contentIndex, delta: call.argumentsJson, partial: output });\n\t}\n}\n\nfunction closeText(output: AssistantMessage, events: AssistantMessageEventStream, state: DevinStreamState): void {\n\tconst index = state.textIndex;\n\tif (index === undefined) return;\n\tconst block = output.content[index];\n\tstate.textIndex = undefined;\n\tif (block?.type === \"text\")\n\t\tevents.push({ type: \"text_end\", contentIndex: index, content: block.text, partial: output });\n}\n\nfunction closeThinking(output: AssistantMessage, events: AssistantMessageEventStream, state: DevinStreamState): void {\n\tconst index = state.thinkingIndex;\n\tif (index === undefined) return;\n\tconst block = output.content[index];\n\tstate.thinkingIndex = undefined;\n\tif (block?.type === \"thinking\")\n\t\tevents.push({ type: \"thinking_end\", contentIndex: index, content: block.thinking, partial: output });\n}\n\nfunction applyUsage(message: GetChatMessageResponse, output: AssistantMessage): void {\n\tconst usage = message.usage;\n\tif (!usage) return;\n\toutput.usage.input = Number(usage.inputTokens);\n\toutput.usage.output = Number(usage.outputTokens);\n\toutput.usage.cacheRead = Number(usage.cacheReadTokens);\n\toutput.usage.cacheWrite = Number(usage.cacheWriteTokens);\n\toutput.usage.totalTokens =\n\t\toutput.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;\n}\n\n/** Cascade's stop vocabulary reduced to senpi's. */\nfunction mapStopReason(reason: StopReason): AssistantMessage[\"stopReason\"] {\n\tswitch (reason) {\n\t\tcase StopReason.FUNCTION_CALL:\n\t\t\treturn \"toolUse\";\n\t\tcase StopReason.MAX_TOKENS:\n\t\tcase StopReason.MAX_NEWLINES:\n\t\t\treturn \"length\";\n\t\tcase StopReason.ERROR:\n\t\tcase StopReason.CONTENT_FILTER:\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"stop\";\n\t}\n}\n\nfunction parseArguments(json: string, fallback: Record<string, unknown>): Record<string, unknown> {\n\tif (!json) return fallback;\n\ttry {\n\t\tconst parsed = JSON.parse(json) as unknown;\n\t\treturn parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)\n\t\t\t? (parsed as Record<string, unknown>)\n\t\t\t: fallback;\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n"]}
1
+ {"version":3,"file":"stream-state.js","sourceRoot":"","sources":["../../../src/api/devin-agent/stream-state.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Cascade delta bookkeeping.\n *\n * One Cascade response frame can carry a thinking delta, a text delta and a\n * finished tool call at once, and blocks are implicit: the server never opens\n * or closes them. This module owns the open-block state so the adapter emits\n * senpi's start/delta/end triples in the right order.\n */\n\nimport type { AssistantMessage, ToolCall } from \"../../types.ts\";\nimport type { AssistantMessageEventStream } from \"../../utils/event-stream.ts\";\nimport { parseStreamingJson } from \"../../utils/json-parse.ts\";\nimport { type GetChatMessageResponse, StopReason } from \"./gen/cascade_pb.ts\";\n\nexport interface DevinToolCallState {\n\tcontentIndex: number;\n\t/** Raw JSON accumulated across chunks; the content block holds the parsed view. */\n\targumentsJson: string;\n}\n\nexport interface DevinStreamState {\n\ttextIndex: number | undefined;\n\tthinkingIndex: number | undefined;\n\ttoolCalls: Map<string, DevinToolCallState>;\n\t/** Chunks after the first arrive without an id; they belong to this call. */\n\tactiveToolCallId: string | undefined;\n}\n\nexport function createDevinStreamState(): DevinStreamState {\n\treturn { textIndex: undefined, thinkingIndex: undefined, toolCalls: new Map(), activeToolCallId: undefined };\n}\n\nexport function applyDevinResponse(\n\tmessage: GetChatMessageResponse,\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\tif (message.messageId && !output.responseId) output.responseId = message.messageId;\n\tif (message.actualModelUid) output.responseModel = message.actualModelUid;\n\n\tif (message.deltaThinking) appendThinking(message, output, events, state);\n\tif (message.deltaText) appendText(message.deltaText, output, events, state);\n\tfor (const call of message.deltaToolCalls) appendToolCall(call, output, events, state);\n\tif (message.usage) applyUsage(message, output);\n\tif (message.stopReason !== StopReason.UNSPECIFIED) output.stopReason = mapStopReason(message.stopReason);\n}\n\nfunction appendThinking(\n\tmessage: GetChatMessageResponse,\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\t// A thinking block interleaved after text starts a new block, matching the\n\t// order Cascade streamed it in.\n\tif (state.textIndex !== undefined) closeText(output, events, state);\n\tif (state.thinkingIndex === undefined) {\n\t\toutput.content.push({ type: \"thinking\", thinking: \"\", ...(message.thinkingRedacted ? { redacted: true } : {}) });\n\t\tstate.thinkingIndex = output.content.length - 1;\n\t\tevents.push({ type: \"thinking_start\", contentIndex: state.thinkingIndex, partial: output });\n\t}\n\tconst block = output.content[state.thinkingIndex];\n\tif (block?.type !== \"thinking\") return;\n\tblock.thinking += message.deltaThinking;\n\tif (message.deltaSignature) block.thinkingSignature = message.deltaSignature;\n\tevents.push({\n\t\ttype: \"thinking_delta\",\n\t\tcontentIndex: state.thinkingIndex,\n\t\tdelta: message.deltaThinking,\n\t\tpartial: output,\n\t});\n}\n\nfunction appendText(\n\tdelta: string,\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\tif (state.thinkingIndex !== undefined) closeThinking(output, events, state);\n\tif (state.textIndex === undefined) {\n\t\toutput.content.push({ type: \"text\", text: \"\" });\n\t\tstate.textIndex = output.content.length - 1;\n\t\tevents.push({ type: \"text_start\", contentIndex: state.textIndex, partial: output });\n\t}\n\tconst block = output.content[state.textIndex];\n\tif (block?.type !== \"text\") return;\n\tblock.text += delta;\n\tevents.push({ type: \"text_delta\", contentIndex: state.textIndex, delta, partial: output });\n}\n\nfunction appendToolCall(\n\tcall: { id: string; name: string; argumentsJson: string },\n\toutput: AssistantMessage,\n\tevents: AssistantMessageEventStream,\n\tstate: DevinStreamState,\n): void {\n\tif (state.textIndex !== undefined) closeText(output, events, state);\n\tif (state.thinkingIndex !== undefined) closeThinking(output, events, state);\n\tconst toolCallId = call.id || state.activeToolCallId;\n\tif (!toolCallId) return;\n\tstate.activeToolCallId = toolCallId;\n\tlet entry = state.toolCalls.get(toolCallId);\n\tif (entry === undefined) {\n\t\tconst block: ToolCall = { type: \"toolCall\", id: toolCallId, name: call.name, arguments: {} };\n\t\toutput.content.push(block);\n\t\tentry = { contentIndex: output.content.length - 1, argumentsJson: \"\" };\n\t\tstate.toolCalls.set(toolCallId, entry);\n\t\tevents.push({ type: \"toolcall_start\", contentIndex: entry.contentIndex, partial: output });\n\t}\n\tconst block = output.content[entry.contentIndex];\n\tif (block?.type !== \"toolCall\") return;\n\tif (call.name) block.name = call.name;\n\tif (!call.argumentsJson) return;\n\t// A chunk either repeats everything so far plus new bytes, or carries only the new bytes.\n\tconst accumulated = call.argumentsJson.startsWith(entry.argumentsJson)\n\t\t? call.argumentsJson\n\t\t: entry.argumentsJson + call.argumentsJson;\n\tconst delta = accumulated.slice(entry.argumentsJson.length);\n\tentry.argumentsJson = accumulated;\n\tblock.arguments = parseStreamingJson(accumulated);\n\tif (delta) events.push({ type: \"toolcall_delta\", contentIndex: entry.contentIndex, delta, partial: output });\n}\n\nfunction closeText(output: AssistantMessage, events: AssistantMessageEventStream, state: DevinStreamState): void {\n\tconst index = state.textIndex;\n\tif (index === undefined) return;\n\tconst block = output.content[index];\n\tstate.textIndex = undefined;\n\tif (block?.type === \"text\")\n\t\tevents.push({ type: \"text_end\", contentIndex: index, content: block.text, partial: output });\n}\n\nfunction closeThinking(output: AssistantMessage, events: AssistantMessageEventStream, state: DevinStreamState): void {\n\tconst index = state.thinkingIndex;\n\tif (index === undefined) return;\n\tconst block = output.content[index];\n\tstate.thinkingIndex = undefined;\n\tif (block?.type === \"thinking\")\n\t\tevents.push({ type: \"thinking_end\", contentIndex: index, content: block.thinking, partial: output });\n}\n\nfunction applyUsage(message: GetChatMessageResponse, output: AssistantMessage): void {\n\tconst usage = message.usage;\n\tif (!usage) return;\n\toutput.usage.input = Number(usage.inputTokens);\n\toutput.usage.output = Number(usage.outputTokens);\n\toutput.usage.cacheRead = Number(usage.cacheReadTokens);\n\toutput.usage.cacheWrite = Number(usage.cacheWriteTokens);\n\toutput.usage.totalTokens =\n\t\toutput.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;\n}\n\n/** Cascade's stop vocabulary reduced to senpi's. */\nfunction mapStopReason(reason: StopReason): AssistantMessage[\"stopReason\"] {\n\tswitch (reason) {\n\t\tcase StopReason.FUNCTION_CALL:\n\t\t\treturn \"toolUse\";\n\t\tcase StopReason.MAX_TOKENS:\n\t\tcase StopReason.MAX_NEWLINES:\n\t\t\treturn \"length\";\n\t\tcase StopReason.ERROR:\n\t\tcase StopReason.CONTENT_FILTER:\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"stop\";\n\t}\n}\n"]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Connect end-of-stream trailer errors.
3
+ *
4
+ * Cascade rejects a turn (`invalid_argument`, `permission_denied`, ...) with an
5
+ * HTTP 200 whose only frame is the trailer `{ error: { code, message, details } }`.
6
+ * The trailer is the sole server-side evidence for such a rejection, so it is
7
+ * parsed with guards - never asserted - and its details are folded into the
8
+ * message a user sees.
9
+ */
10
+ export interface DevinTrailerError {
11
+ code: string;
12
+ message: string;
13
+ formatted: string;
14
+ }
15
+ export declare function readDevinTrailerError(trailer: string): DevinTrailerError | undefined;
16
+ //# sourceMappingURL=trailer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trailer.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/trailer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAmBpF"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Connect end-of-stream trailer errors.
3
+ *
4
+ * Cascade rejects a turn (`invalid_argument`, `permission_denied`, ...) with an
5
+ * HTTP 200 whose only frame is the trailer `{ error: { code, message, details } }`.
6
+ * The trailer is the sole server-side evidence for such a rejection, so it is
7
+ * parsed with guards - never asserted - and its details are folded into the
8
+ * message a user sees.
9
+ */
10
+ const MAX_TRAILER_EVIDENCE_CHARS = 2000;
11
+ export function readDevinTrailerError(trailer) {
12
+ const text = trailer.trim();
13
+ if (!text)
14
+ return undefined;
15
+ let parsed;
16
+ try {
17
+ parsed = JSON.parse(text);
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ if (!isRecord(parsed) || !isRecord(parsed.error))
23
+ return undefined;
24
+ const code = typeof parsed.error.code === "string" ? parsed.error.code : "";
25
+ const message = typeof parsed.error.message === "string" ? parsed.error.message : "";
26
+ if (!code && !message)
27
+ return undefined;
28
+ const detail = summarizeDetails(parsed.error.details);
29
+ return {
30
+ code,
31
+ message,
32
+ formatted: `Devin stream error${code ? ` ${code}` : ""}: ${message}${detail ? ` [details: ${detail}]` : ""}`,
33
+ };
34
+ }
35
+ function summarizeDetails(details) {
36
+ if (!Array.isArray(details) || details.length === 0)
37
+ return undefined;
38
+ const parts = [];
39
+ for (const entry of details) {
40
+ if (!isRecord(entry))
41
+ continue;
42
+ const type = typeof entry.type === "string" && entry.type ? entry.type : undefined;
43
+ const evidence = evidenceOf(entry);
44
+ const part = type && evidence ? `${type}: ${evidence}` : (type ?? evidence);
45
+ if (part)
46
+ parts.push(part);
47
+ }
48
+ const summary = parts.join("; ");
49
+ if (!summary)
50
+ return undefined;
51
+ return summary.length > MAX_TRAILER_EVIDENCE_CHARS ? `${summary.slice(0, MAX_TRAILER_EVIDENCE_CHARS)}…` : summary;
52
+ }
53
+ function evidenceOf(entry) {
54
+ if (entry.debug !== undefined) {
55
+ if (typeof entry.debug === "string")
56
+ return entry.debug;
57
+ try {
58
+ return JSON.stringify(entry.debug);
59
+ }
60
+ catch {
61
+ return undefined;
62
+ }
63
+ }
64
+ return typeof entry.value === "string" && entry.value ? entry.value : undefined;
65
+ }
66
+ function isRecord(value) {
67
+ return typeof value === "object" && value !== null && !Array.isArray(value);
68
+ }
69
+ //# sourceMappingURL=trailer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trailer.js","sourceRoot":"","sources":["../../../src/api/devin-agent/trailer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAQxC,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACnE,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtD,OAAO;QACN,IAAI;QACJ,OAAO;QACP,SAAS,EAAE,qBAAqB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;KAC5G,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAgB;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACtE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/B,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACnF,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC;QAC5E,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,OAAO,CAAC,MAAM,GAAG,0BAA0B,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,0BAA0B,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AACnH,CAAC;AAED,SAAS,UAAU,CAAC,KAA8B;IACjD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC;QACxD,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IACD,OAAO,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["/**\n * Connect end-of-stream trailer errors.\n *\n * Cascade rejects a turn (`invalid_argument`, `permission_denied`, ...) with an\n * HTTP 200 whose only frame is the trailer `{ error: { code, message, details } }`.\n * The trailer is the sole server-side evidence for such a rejection, so it is\n * parsed with guards - never asserted - and its details are folded into the\n * message a user sees.\n */\n\nconst MAX_TRAILER_EVIDENCE_CHARS = 2000;\n\nexport interface DevinTrailerError {\n\tcode: string;\n\tmessage: string;\n\tformatted: string;\n}\n\nexport function readDevinTrailerError(trailer: string): DevinTrailerError | undefined {\n\tconst text = trailer.trim();\n\tif (!text) return undefined;\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!isRecord(parsed) || !isRecord(parsed.error)) return undefined;\n\tconst code = typeof parsed.error.code === \"string\" ? parsed.error.code : \"\";\n\tconst message = typeof parsed.error.message === \"string\" ? parsed.error.message : \"\";\n\tif (!code && !message) return undefined;\n\tconst detail = summarizeDetails(parsed.error.details);\n\treturn {\n\t\tcode,\n\t\tmessage,\n\t\tformatted: `Devin stream error${code ? ` ${code}` : \"\"}: ${message}${detail ? ` [details: ${detail}]` : \"\"}`,\n\t};\n}\n\nfunction summarizeDetails(details: unknown): string | undefined {\n\tif (!Array.isArray(details) || details.length === 0) return undefined;\n\tconst parts: string[] = [];\n\tfor (const entry of details) {\n\t\tif (!isRecord(entry)) continue;\n\t\tconst type = typeof entry.type === \"string\" && entry.type ? entry.type : undefined;\n\t\tconst evidence = evidenceOf(entry);\n\t\tconst part = type && evidence ? `${type}: ${evidence}` : (type ?? evidence);\n\t\tif (part) parts.push(part);\n\t}\n\tconst summary = parts.join(\"; \");\n\tif (!summary) return undefined;\n\treturn summary.length > MAX_TRAILER_EVIDENCE_CHARS ? `${summary.slice(0, MAX_TRAILER_EVIDENCE_CHARS)}…` : summary;\n}\n\nfunction evidenceOf(entry: Record<string, unknown>): string | undefined {\n\tif (entry.debug !== undefined) {\n\t\tif (typeof entry.debug === \"string\") return entry.debug;\n\t\ttry {\n\t\t\treturn JSON.stringify(entry.debug);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn typeof entry.value === \"string\" && entry.value ? entry.value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"]}