@orthacms/copilot-server 0.0.0-reserve.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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/index.d.ts +24 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +48 -0
  6. package/dist/lib/chat/application/appliers-registrar.d.ts +16 -0
  7. package/dist/lib/chat/application/appliers-registrar.d.ts.map +1 -0
  8. package/dist/lib/chat/application/appliers-registrar.js +50 -0
  9. package/dist/lib/chat/application/capability-profile.service.d.ts +43 -0
  10. package/dist/lib/chat/application/capability-profile.service.d.ts.map +1 -0
  11. package/dist/lib/chat/application/capability-profile.service.js +75 -0
  12. package/dist/lib/chat/application/content-type-summary.service.d.ts +32 -0
  13. package/dist/lib/chat/application/content-type-summary.service.d.ts.map +1 -0
  14. package/dist/lib/chat/application/content-type-summary.service.js +64 -0
  15. package/dist/lib/chat/application/decide-proposal.service.d.ts +80 -0
  16. package/dist/lib/chat/application/decide-proposal.service.d.ts.map +1 -0
  17. package/dist/lib/chat/application/decide-proposal.service.js +112 -0
  18. package/dist/lib/chat/application/dto/create-run.dto.d.ts +138 -0
  19. package/dist/lib/chat/application/dto/create-run.dto.d.ts.map +1 -0
  20. package/dist/lib/chat/application/dto/create-run.dto.js +253 -0
  21. package/dist/lib/chat/application/dto/decide-tool-permission.dto.d.ts +20 -0
  22. package/dist/lib/chat/application/dto/decide-tool-permission.dto.d.ts.map +1 -0
  23. package/dist/lib/chat/application/dto/decide-tool-permission.dto.js +44 -0
  24. package/dist/lib/chat/application/dto/extend-tool-permission.dto.d.ts +18 -0
  25. package/dist/lib/chat/application/dto/extend-tool-permission.dto.d.ts.map +1 -0
  26. package/dist/lib/chat/application/dto/extend-tool-permission.dto.js +33 -0
  27. package/dist/lib/chat/application/dto/list-conversations-query.dto.d.ts +18 -0
  28. package/dist/lib/chat/application/dto/list-conversations-query.dto.d.ts.map +1 -0
  29. package/dist/lib/chat/application/dto/list-conversations-query.dto.js +39 -0
  30. package/dist/lib/chat/application/dto/list-proposals-query.dto.d.ts +15 -0
  31. package/dist/lib/chat/application/dto/list-proposals-query.dto.d.ts.map +1 -0
  32. package/dist/lib/chat/application/dto/list-proposals-query.dto.js +41 -0
  33. package/dist/lib/chat/application/dto/update-conversation.dto.d.ts +68 -0
  34. package/dist/lib/chat/application/dto/update-conversation.dto.d.ts.map +1 -0
  35. package/dist/lib/chat/application/dto/update-conversation.dto.js +115 -0
  36. package/dist/lib/chat/application/proposal-applier.registry.d.ts +27 -0
  37. package/dist/lib/chat/application/proposal-applier.registry.d.ts.map +1 -0
  38. package/dist/lib/chat/application/proposal-applier.registry.js +62 -0
  39. package/dist/lib/chat/application/run-engine.service.d.ts +243 -0
  40. package/dist/lib/chat/application/run-engine.service.d.ts.map +1 -0
  41. package/dist/lib/chat/application/run-engine.service.js +1058 -0
  42. package/dist/lib/chat/application/summarize-tool-output.d.ts +15 -0
  43. package/dist/lib/chat/application/summarize-tool-output.d.ts.map +1 -0
  44. package/dist/lib/chat/application/summarize-tool-output.js +61 -0
  45. package/dist/lib/chat/application/system-prompt.d.ts +81 -0
  46. package/dist/lib/chat/application/system-prompt.d.ts.map +1 -0
  47. package/dist/lib/chat/application/system-prompt.js +477 -0
  48. package/dist/lib/chat/application/tool-permission.broker.d.ts +118 -0
  49. package/dist/lib/chat/application/tool-permission.broker.d.ts.map +1 -0
  50. package/dist/lib/chat/application/tool-permission.broker.js +221 -0
  51. package/dist/lib/chat/http/controllers/create-run.controller.d.ts +30 -0
  52. package/dist/lib/chat/http/controllers/create-run.controller.d.ts.map +1 -0
  53. package/dist/lib/chat/http/controllers/create-run.controller.js +159 -0
  54. package/dist/lib/chat/http/controllers/get-conversation.controller.d.ts +22 -0
  55. package/dist/lib/chat/http/controllers/get-conversation.controller.d.ts.map +1 -0
  56. package/dist/lib/chat/http/controllers/get-conversation.controller.js +50 -0
  57. package/dist/lib/chat/http/controllers/list-conversations.controller.d.ts +20 -0
  58. package/dist/lib/chat/http/controllers/list-conversations.controller.d.ts.map +1 -0
  59. package/dist/lib/chat/http/controllers/list-conversations.controller.js +47 -0
  60. package/dist/lib/chat/http/controllers/list-models.controller.d.ts +35 -0
  61. package/dist/lib/chat/http/controllers/list-models.controller.d.ts.map +1 -0
  62. package/dist/lib/chat/http/controllers/list-models.controller.js +48 -0
  63. package/dist/lib/chat/http/controllers/proposals.controller.d.ts +43 -0
  64. package/dist/lib/chat/http/controllers/proposals.controller.d.ts.map +1 -0
  65. package/dist/lib/chat/http/controllers/proposals.controller.js +98 -0
  66. package/dist/lib/chat/http/controllers/tool-permission.controller.d.ts +57 -0
  67. package/dist/lib/chat/http/controllers/tool-permission.controller.d.ts.map +1 -0
  68. package/dist/lib/chat/http/controllers/tool-permission.controller.js +116 -0
  69. package/dist/lib/chat/http/controllers/update-conversation.controller.d.ts +37 -0
  70. package/dist/lib/chat/http/controllers/update-conversation.controller.d.ts.map +1 -0
  71. package/dist/lib/chat/http/controllers/update-conversation.controller.js +108 -0
  72. package/dist/lib/chat/http/sse-stream.d.ts +41 -0
  73. package/dist/lib/chat/http/sse-stream.d.ts.map +1 -0
  74. package/dist/lib/chat/http/sse-stream.js +95 -0
  75. package/dist/lib/chat/infrastructure/persistence/conversation.repository.d.ts +159 -0
  76. package/dist/lib/chat/infrastructure/persistence/conversation.repository.d.ts.map +1 -0
  77. package/dist/lib/chat/infrastructure/persistence/conversation.repository.js +249 -0
  78. package/dist/lib/chat/infrastructure/persistence/derive-title.d.ts +13 -0
  79. package/dist/lib/chat/infrastructure/persistence/derive-title.d.ts.map +1 -0
  80. package/dist/lib/chat/infrastructure/persistence/derive-title.js +35 -0
  81. package/dist/lib/chat/infrastructure/persistence/proposal.repository.d.ts +86 -0
  82. package/dist/lib/chat/infrastructure/persistence/proposal.repository.d.ts.map +1 -0
  83. package/dist/lib/chat/infrastructure/persistence/proposal.repository.js +152 -0
  84. package/dist/lib/chat/infrastructure/schema/conversations.d.ts +189 -0
  85. package/dist/lib/chat/infrastructure/schema/conversations.d.ts.map +1 -0
  86. package/dist/lib/chat/infrastructure/schema/conversations.js +100 -0
  87. package/dist/lib/chat/infrastructure/schema/external-refs.d.ts +67 -0
  88. package/dist/lib/chat/infrastructure/schema/external-refs.d.ts.map +1 -0
  89. package/dist/lib/chat/infrastructure/schema/external-refs.js +28 -0
  90. package/dist/lib/chat/infrastructure/schema/index.d.ts +5 -0
  91. package/dist/lib/chat/infrastructure/schema/index.d.ts.map +1 -0
  92. package/dist/lib/chat/infrastructure/schema/index.js +12 -0
  93. package/dist/lib/chat/infrastructure/schema/messages.d.ts +264 -0
  94. package/dist/lib/chat/infrastructure/schema/messages.d.ts.map +1 -0
  95. package/dist/lib/chat/infrastructure/schema/messages.js +96 -0
  96. package/dist/lib/chat/infrastructure/schema/proposals.d.ts +328 -0
  97. package/dist/lib/chat/infrastructure/schema/proposals.d.ts.map +1 -0
  98. package/dist/lib/chat/infrastructure/schema/proposals.js +87 -0
  99. package/dist/lib/chat/infrastructure/schema/tool-calls.d.ts +203 -0
  100. package/dist/lib/chat/infrastructure/schema/tool-calls.d.ts.map +1 -0
  101. package/dist/lib/chat/infrastructure/schema/tool-calls.js +50 -0
  102. package/dist/lib/copilot.module.d.ts +30 -0
  103. package/dist/lib/copilot.module.d.ts.map +1 -0
  104. package/dist/lib/copilot.module.js +146 -0
  105. package/dist/lib/copilot.tokens.d.ts +34 -0
  106. package/dist/lib/copilot.tokens.d.ts.map +1 -0
  107. package/dist/lib/copilot.tokens.js +38 -0
  108. package/dist/lib/infrastructure/model-registry.d.ts +22 -0
  109. package/dist/lib/infrastructure/model-registry.d.ts.map +1 -0
  110. package/dist/lib/infrastructure/model-registry.js +54 -0
  111. package/dist/lib/skills/application/dto/create-skill.dto.d.ts +36 -0
  112. package/dist/lib/skills/application/dto/create-skill.dto.d.ts.map +1 -0
  113. package/dist/lib/skills/application/dto/create-skill.dto.js +106 -0
  114. package/dist/lib/skills/application/dto/update-skill.dto.d.ts +28 -0
  115. package/dist/lib/skills/application/dto/update-skill.dto.d.ts.map +1 -0
  116. package/dist/lib/skills/application/dto/update-skill.dto.js +96 -0
  117. package/dist/lib/skills/application/skill-catalog.service.d.ts +97 -0
  118. package/dist/lib/skills/application/skill-catalog.service.d.ts.map +1 -0
  119. package/dist/lib/skills/application/skill-catalog.service.js +157 -0
  120. package/dist/lib/skills/http/controllers/list-skills.controller.d.ts +19 -0
  121. package/dist/lib/skills/http/controllers/list-skills.controller.d.ts.map +1 -0
  122. package/dist/lib/skills/http/controllers/list-skills.controller.js +50 -0
  123. package/dist/lib/skills/http/controllers/manage-skills.controller.d.ts +64 -0
  124. package/dist/lib/skills/http/controllers/manage-skills.controller.d.ts.map +1 -0
  125. package/dist/lib/skills/http/controllers/manage-skills.controller.js +182 -0
  126. package/dist/lib/skills/infrastructure/persistence/skill.repository.d.ts +78 -0
  127. package/dist/lib/skills/infrastructure/persistence/skill.repository.d.ts.map +1 -0
  128. package/dist/lib/skills/infrastructure/persistence/skill.repository.js +116 -0
  129. package/dist/lib/skills/infrastructure/schema/index.d.ts +2 -0
  130. package/dist/lib/skills/infrastructure/schema/index.d.ts.map +1 -0
  131. package/dist/lib/skills/infrastructure/schema/index.js +6 -0
  132. package/dist/lib/skills/infrastructure/schema/skills.d.ts +212 -0
  133. package/dist/lib/skills/infrastructure/schema/skills.d.ts.map +1 -0
  134. package/dist/lib/skills/infrastructure/schema/skills.js +78 -0
  135. package/dist/lib/types/copilot-config.d.ts +55 -0
  136. package/dist/lib/types/copilot-config.d.ts.map +1 -0
  137. package/dist/lib/types/copilot-config.js +2 -0
  138. package/dist/lib/utils/copilot-plugin.d.ts +66 -0
  139. package/dist/lib/utils/copilot-plugin.d.ts.map +1 -0
  140. package/dist/lib/utils/copilot-plugin.js +87 -0
  141. package/migrations/0000_copilot_chat.sql +48 -0
  142. package/migrations/0001_proposals.sql +34 -0
  143. package/migrations/0002_drop_workspace_policies.sql +1 -0
  144. package/migrations/0003_conversation_allowed_tools.sql +1 -0
  145. package/migrations/0004_message_attachments.sql +1 -0
  146. package/migrations/0005_skills.sql +19 -0
  147. package/migrations/0006_conversation_model_choice.sql +1 -0
  148. package/migrations/meta/0000_snapshot.json +390 -0
  149. package/migrations/meta/0001_snapshot.json +657 -0
  150. package/migrations/meta/0002_snapshot.json +610 -0
  151. package/migrations/meta/0003_snapshot.json +617 -0
  152. package/migrations/meta/0004_snapshot.json +623 -0
  153. package/migrations/meta/0005_snapshot.json +771 -0
  154. package/migrations/meta/0006_snapshot.json +777 -0
  155. package/migrations/meta/_journal.json +55 -0
  156. package/package.json +46 -0
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListConversationsController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const identity_server_1 = require("@orthacms/identity-server");
8
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
9
+ const conversation_repository_1 = require("../../infrastructure/persistence/conversation.repository");
10
+ const list_conversations_query_dto_1 = require("../../application/dto/list-conversations-query.dto");
11
+ /**
12
+ * `GET /api/copilot/conversations` — the signed-in user's threads in the open
13
+ * workspace, most recently used first.
14
+ *
15
+ * No `OriginGuard`: it guards state-changing requests, and this reads. The
16
+ * scoping that matters is in the repository, which filters on user **and**
17
+ * workspace — the guard proves the caller belongs to the workspace, and the
18
+ * query proves the threads belong to the caller.
19
+ */
20
+ let ListConversationsController = class ListConversationsController {
21
+ conversations;
22
+ constructor(conversations) {
23
+ this.conversations = conversations;
24
+ }
25
+ async list(query, user, workspaceId) {
26
+ return {
27
+ items: await this.conversations.list(user.id, workspaceId, query.archived ?? false)
28
+ };
29
+ }
30
+ };
31
+ exports.ListConversationsController = ListConversationsController;
32
+ tslib_1.__decorate([
33
+ (0, common_1.Get)('conversations'),
34
+ (0, swagger_1.ApiOperation)({ summary: 'List the current user’s copilot conversations' }),
35
+ tslib_1.__param(0, (0, common_1.Query)()),
36
+ tslib_1.__param(1, (0, identity_server_1.CurrentUser)()),
37
+ tslib_1.__param(2, (0, workspaces_server_1.CurrentWorkspace)()),
38
+ tslib_1.__metadata("design:type", Function),
39
+ tslib_1.__metadata("design:paramtypes", [list_conversations_query_dto_1.ListConversationsQueryDto, Object, String]),
40
+ tslib_1.__metadata("design:returntype", Promise)
41
+ ], ListConversationsController.prototype, "list", null);
42
+ exports.ListConversationsController = ListConversationsController = tslib_1.__decorate([
43
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard, workspaces_server_1.WorkspaceGuard),
44
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.COPILOT_USE),
45
+ (0, common_1.Controller)('copilot'),
46
+ tslib_1.__metadata("design:paramtypes", [conversation_repository_1.ConversationRepository])
47
+ ], ListConversationsController);
@@ -0,0 +1,35 @@
1
+ import { type ModelChoice, type ModelRegistry } from '@orthacms/copilot-domain';
2
+ /** What the model picker renders. */
3
+ export interface ModelCatalogue {
4
+ /**
5
+ * Every provider × model pair on offer, in registration order.
6
+ *
7
+ * The order carries the only default there is: `items[0]` is the first
8
+ * registered provider's first model, which is what a run that names
9
+ * neither gets, and what the picker opens on. There is no separate
10
+ * `defaultProvider` field for a client to reconcile with this list.
11
+ */
12
+ items: ModelChoice[];
13
+ }
14
+ /**
15
+ * `GET /api/copilot/models` — the backends a run may choose from.
16
+ *
17
+ * This is `ModelRegistry.catalogue()` served verbatim, which is what phase 0
18
+ * built it for: a user switches model mid-conversation by picking another row,
19
+ * and an operator changes what is on offer by changing the provider list in
20
+ * `plugins.ts` — the list is the whole configuration. The registry is
21
+ * fixed at boot from `plugins.ts`, so this leaks nothing an operator did not
22
+ * already choose to offer — **names only**, never a credential or a base URL.
23
+ *
24
+ * No `WorkspaceGuard`: the catalogue is deployment-wide, not workspace-owned,
25
+ * and the picker renders before a workspace is necessarily resolved. Gated on
26
+ * `copilot:use` like the rest of the surface. (Registering models at runtime,
27
+ * with encrypted credentials, is the separate phase-4 surface behind
28
+ * `copilot:configure`.)
29
+ */
30
+ export declare class ListModelsController {
31
+ private readonly registry;
32
+ constructor(registry: ModelRegistry);
33
+ list(): ModelCatalogue;
34
+ }
35
+ //# sourceMappingURL=list-models.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-models.controller.d.ts","sourceRoot":"","sources":["../../../../../src/lib/chat/http/controllers/list-models.controller.ts"],"names":[],"mappings":"AAEA,OAAO,EAEH,KAAK,WAAW,EAChB,KAAK,aAAa,EACrB,MAAM,0BAA0B,CAAC;AAOlC,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC3B;;;;;;;OAOG;IACH,KAAK,EAAE,WAAW,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAGa,oBAAoB;IAED,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,aAAa;IAKpE,IAAI,IAAI,cAAc;CAGzB"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListModelsController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const copilot_domain_1 = require("@orthacms/copilot-domain");
8
+ const identity_server_1 = require("@orthacms/identity-server");
9
+ /**
10
+ * `GET /api/copilot/models` — the backends a run may choose from.
11
+ *
12
+ * This is `ModelRegistry.catalogue()` served verbatim, which is what phase 0
13
+ * built it for: a user switches model mid-conversation by picking another row,
14
+ * and an operator changes what is on offer by changing the provider list in
15
+ * `plugins.ts` — the list is the whole configuration. The registry is
16
+ * fixed at boot from `plugins.ts`, so this leaks nothing an operator did not
17
+ * already choose to offer — **names only**, never a credential or a base URL.
18
+ *
19
+ * No `WorkspaceGuard`: the catalogue is deployment-wide, not workspace-owned,
20
+ * and the picker renders before a workspace is necessarily resolved. Gated on
21
+ * `copilot:use` like the rest of the surface. (Registering models at runtime,
22
+ * with encrypted credentials, is the separate phase-4 surface behind
23
+ * `copilot:configure`.)
24
+ */
25
+ let ListModelsController = class ListModelsController {
26
+ registry;
27
+ constructor(registry) {
28
+ this.registry = registry;
29
+ }
30
+ list() {
31
+ return { items: this.registry.catalogue() };
32
+ }
33
+ };
34
+ exports.ListModelsController = ListModelsController;
35
+ tslib_1.__decorate([
36
+ (0, common_1.Get)('models'),
37
+ (0, swagger_1.ApiOperation)({ summary: 'List the model backends a run may choose from' }),
38
+ tslib_1.__metadata("design:type", Function),
39
+ tslib_1.__metadata("design:paramtypes", []),
40
+ tslib_1.__metadata("design:returntype", Object)
41
+ ], ListModelsController.prototype, "list", null);
42
+ exports.ListModelsController = ListModelsController = tslib_1.__decorate([
43
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard),
44
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.COPILOT_USE),
45
+ (0, common_1.Controller)('copilot'),
46
+ tslib_1.__param(0, (0, common_1.Inject)(copilot_domain_1.MODEL_REGISTRY)),
47
+ tslib_1.__metadata("design:paramtypes", [Object])
48
+ ], ListModelsController);
@@ -0,0 +1,43 @@
1
+ import { type PublicUser } from '@orthacms/identity-server';
2
+ import { ProposalRepository, type ProposalView } from '../../infrastructure/persistence/proposal.repository';
3
+ import { ConversationRepository } from '../../infrastructure/persistence/conversation.repository';
4
+ import { ListProposalsQueryDto } from '../../application/dto/list-proposals-query.dto';
5
+ /**
6
+ * `GET /api/copilot/proposals…` — the record of what the copilot changed.
7
+ *
8
+ * **Reads only.** These used to sit alongside `accept` and `reject`, and this
9
+ * was the accept boundary
10
+ * ([ADR-0005](../../../../../../docs/adr/0005-copilot-authority-model.md) §5).
11
+ * [ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)
12
+ * removed the human step, so a proposal is now a **receipt** rather than a
13
+ * decision waiting to be made: the engine applies it as it is drafted, and what
14
+ * is left to serve is the row saying what happened.
15
+ *
16
+ * They are still worth serving, and both callers prove it: the chat panel joins
17
+ * them onto a reopened thread so the cards come back, and the row is the paper
18
+ * trail a change made without review depends on. Keeping the read while
19
+ * deleting the write is the point — "undoable, never invisible" is now carried
20
+ * entirely by this record.
21
+ *
22
+ * No `OriginGuard`: nothing here is state-changing any more.
23
+ */
24
+ export declare class ProposalsController {
25
+ private readonly proposals;
26
+ private readonly conversations;
27
+ constructor(proposals: ProposalRepository, conversations: ConversationRepository);
28
+ /**
29
+ * The list is **workspace**-scoped, not user-scoped, and that is the right
30
+ * shape: a proposal is the receipt for a change to the workspace's content,
31
+ * and every member can already read that content. What it must not become
32
+ * is a way to learn about someone else's *thread* — `GET
33
+ * /conversations/:id` 404s a thread that is not yours, and a filter that
34
+ * answered "yes, that id is in this workspace" would undo it from the other
35
+ * side. So the filter is only honoured for a conversation the caller owns;
36
+ * anything else is the same 404 the conversation route gives.
37
+ */
38
+ list(query: ListProposalsQueryDto, user: PublicUser, workspaceId: string): Promise<{
39
+ items: ProposalView[];
40
+ }>;
41
+ get(id: string, workspaceId: string): Promise<ProposalView>;
42
+ }
43
+ //# sourceMappingURL=proposals.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposals.controller.d.ts","sourceRoot":"","sources":["../../../../../src/lib/chat/http/controllers/proposals.controller.ts"],"names":[],"mappings":"AAUA,OAAO,EAKH,KAAK,UAAU,EAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,kBAAkB,EAClB,KAAK,YAAY,EACpB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0DAA0D,CAAC;AAClG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AAEvF;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAGa,mBAAmB;IAExB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa;gBADb,SAAS,EAAE,kBAAkB,EAC7B,aAAa,EAAE,sBAAsB;IAG1D;;;;;;;;;OASG;IAGG,IAAI,CACG,KAAK,EAAE,qBAAqB,EACtB,IAAI,EAAE,UAAU,EACX,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC;QAAE,KAAK,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IAyB/B,GAAG,CACuB,EAAE,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,YAAY,CAAC;CAO3B"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProposalsController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const identity_server_1 = require("@orthacms/identity-server");
8
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
9
+ const proposal_repository_1 = require("../../infrastructure/persistence/proposal.repository");
10
+ const conversation_repository_1 = require("../../infrastructure/persistence/conversation.repository");
11
+ const list_proposals_query_dto_1 = require("../../application/dto/list-proposals-query.dto");
12
+ /**
13
+ * `GET /api/copilot/proposals…` — the record of what the copilot changed.
14
+ *
15
+ * **Reads only.** These used to sit alongside `accept` and `reject`, and this
16
+ * was the accept boundary
17
+ * ([ADR-0005](../../../../../../docs/adr/0005-copilot-authority-model.md) §5).
18
+ * [ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)
19
+ * removed the human step, so a proposal is now a **receipt** rather than a
20
+ * decision waiting to be made: the engine applies it as it is drafted, and what
21
+ * is left to serve is the row saying what happened.
22
+ *
23
+ * They are still worth serving, and both callers prove it: the chat panel joins
24
+ * them onto a reopened thread so the cards come back, and the row is the paper
25
+ * trail a change made without review depends on. Keeping the read while
26
+ * deleting the write is the point — "undoable, never invisible" is now carried
27
+ * entirely by this record.
28
+ *
29
+ * No `OriginGuard`: nothing here is state-changing any more.
30
+ */
31
+ let ProposalsController = class ProposalsController {
32
+ proposals;
33
+ conversations;
34
+ constructor(proposals, conversations) {
35
+ this.proposals = proposals;
36
+ this.conversations = conversations;
37
+ }
38
+ /**
39
+ * The list is **workspace**-scoped, not user-scoped, and that is the right
40
+ * shape: a proposal is the receipt for a change to the workspace's content,
41
+ * and every member can already read that content. What it must not become
42
+ * is a way to learn about someone else's *thread* — `GET
43
+ * /conversations/:id` 404s a thread that is not yours, and a filter that
44
+ * answered "yes, that id is in this workspace" would undo it from the other
45
+ * side. So the filter is only honoured for a conversation the caller owns;
46
+ * anything else is the same 404 the conversation route gives.
47
+ */
48
+ async list(query, user, workspaceId) {
49
+ if (query.conversationId) {
50
+ const thread = await this.conversations.find(query.conversationId, user.id, workspaceId);
51
+ if (!thread) {
52
+ throw new common_1.NotFoundException(`No conversation "${query.conversationId}".`);
53
+ }
54
+ }
55
+ return {
56
+ items: await this.proposals.list(workspaceId, {
57
+ ...(query.status ? { status: query.status } : {}),
58
+ ...(query.conversationId
59
+ ? { conversationId: query.conversationId }
60
+ : {})
61
+ })
62
+ };
63
+ }
64
+ async get(id, workspaceId) {
65
+ const proposal = await this.proposals.find(id, workspaceId);
66
+ if (!proposal) {
67
+ throw new common_1.NotFoundException(`No proposal "${id}".`);
68
+ }
69
+ return proposal;
70
+ }
71
+ };
72
+ exports.ProposalsController = ProposalsController;
73
+ tslib_1.__decorate([
74
+ (0, common_1.Get)('proposals'),
75
+ (0, swagger_1.ApiOperation)({ summary: 'List the workspace’s copilot changes' }),
76
+ tslib_1.__param(0, (0, common_1.Query)()),
77
+ tslib_1.__param(1, (0, identity_server_1.CurrentUser)()),
78
+ tslib_1.__param(2, (0, workspaces_server_1.CurrentWorkspace)()),
79
+ tslib_1.__metadata("design:type", Function),
80
+ tslib_1.__metadata("design:paramtypes", [list_proposals_query_dto_1.ListProposalsQueryDto, Object, String]),
81
+ tslib_1.__metadata("design:returntype", Promise)
82
+ ], ProposalsController.prototype, "list", null);
83
+ tslib_1.__decorate([
84
+ (0, common_1.Get)('proposals/:id'),
85
+ (0, swagger_1.ApiOperation)({ summary: 'Read one copilot change' }),
86
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
87
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
88
+ tslib_1.__metadata("design:type", Function),
89
+ tslib_1.__metadata("design:paramtypes", [String, String]),
90
+ tslib_1.__metadata("design:returntype", Promise)
91
+ ], ProposalsController.prototype, "get", null);
92
+ exports.ProposalsController = ProposalsController = tslib_1.__decorate([
93
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard, workspaces_server_1.WorkspaceGuard),
94
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.COPILOT_USE),
95
+ (0, common_1.Controller)('copilot'),
96
+ tslib_1.__metadata("design:paramtypes", [proposal_repository_1.ProposalRepository,
97
+ conversation_repository_1.ConversationRepository])
98
+ ], ProposalsController);
@@ -0,0 +1,57 @@
1
+ import { type PublicUser } from '@orthacms/identity-server';
2
+ import { ToolPermissionBroker } from '../../application/tool-permission.broker';
3
+ import { DecideToolPermissionDto } from '../../application/dto/decide-tool-permission.dto';
4
+ import { ExtendToolPermissionDto } from '../../application/dto/extend-tool-permission.dto';
5
+ /**
6
+ * `POST /api/copilot/runs/:runId/permission` — the answer to a parked run.
7
+ *
8
+ * **A second request against a run that is still streaming**, which is the only
9
+ * shape available: the run is an SSE response, and a response cannot be asked
10
+ * questions. The run yields a `tool-permission-request` carrying its `runId`
11
+ * and the call id, and this route resolves the promise it is awaiting.
12
+ *
13
+ * It intentionally does **not** re-check whether the caller may use the tool.
14
+ * That is not a gap: the offer filtered it, and `executeTool` re-authorizes
15
+ * against freshly resolved grants immediately after this returns. What this
16
+ * route decides is whether the user *wants* the call to happen, which is a
17
+ * different question from whether they are allowed to make it — and answering
18
+ * "yes" to a tool their role has since lost still ends in a refusal downstream.
19
+ *
20
+ * It very much **does** check whose run it is, and the guards above cannot do
21
+ * it for us. `copilot:use` is held by every role including viewers, and
22
+ * `WorkspaceGuard` proves the caller belongs to *the workspace they named* —
23
+ * neither says anything about the run. Without the owner check a colleague
24
+ * could allow (or refuse) a write in someone else's chat, and a member of an
25
+ * unrelated workspace could do it by naming their own: the `runId` is not a
26
+ * secret, it is handed to the client in the `run-started` frame.
27
+ *
28
+ * The 404 is load-bearing rather than cosmetic, and it is deliberately the same
29
+ * answer for "nothing is waiting" and "not yours". Nothing waiting means the
30
+ * decision arrived after the timeout, or the run is parked on another instance
31
+ * (the broker is in-memory — see its notes). Both are worth telling the client
32
+ * about, because in both cases the answer it just gave had no effect — and
33
+ * whether someone else's run exists is not information this route hands out.
34
+ */
35
+ export declare class ToolPermissionController {
36
+ private readonly broker;
37
+ constructor(broker: ToolPermissionBroker);
38
+ decide(runId: string, body: DecideToolPermissionDto, user: PublicUser, workspaceId: string): void;
39
+ /**
40
+ * `POST /api/copilot/runs/:runId/permission/extend` — "I need more time".
41
+ *
42
+ * The prompt used to have a five-minute limit with no warning, no countdown
43
+ * and no way to ask for longer: it simply disappeared, and the model
44
+ * reported that nobody had answered. WCAG 2.2.1 requires that a time limit
45
+ * set by the content can be turned off, adjusted, or **extended after a
46
+ * warning** — and none of its exceptions apply here, since
47
+ * [ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)
48
+ * justifies the limit as cost, not correctness (`ORT-118`).
49
+ *
50
+ * Same guards, same ownership check and same 404 as {@link decide}: this
51
+ * grants time on a parked run, so who may ask is exactly who may answer.
52
+ */
53
+ extend(runId: string, body: ExtendToolPermissionDto, user: PublicUser, workspaceId: string): {
54
+ expiresAt: string;
55
+ };
56
+ }
57
+ //# sourceMappingURL=tool-permission.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-permission.controller.d.ts","sourceRoot":"","sources":["../../../../../src/lib/chat/http/controllers/tool-permission.controller.ts"],"names":[],"mappings":"AAWA,OAAO,EAMH,KAAK,UAAU,EAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAE3F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAGa,wBAAwB;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,oBAAoB;IAQzD,MAAM,CAC6B,KAAK,EAAE,MAAM,EACpC,IAAI,EAAE,uBAAuB,EACtB,IAAI,EAAE,UAAU,EACX,WAAW,EAAE,MAAM,GACxC,IAAI;IAiBP;;;;;;;;;;;;;OAaG;IAMH,MAAM,CAC6B,KAAK,EAAE,MAAM,EACpC,IAAI,EAAE,uBAAuB,EACtB,IAAI,EAAE,UAAU,EACX,WAAW,EAAE,MAAM,GACxC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE;CAY3B"}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolPermissionController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const identity_server_1 = require("@orthacms/identity-server");
8
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
9
+ const tool_permission_broker_1 = require("../../application/tool-permission.broker");
10
+ const decide_tool_permission_dto_1 = require("../../application/dto/decide-tool-permission.dto");
11
+ const extend_tool_permission_dto_1 = require("../../application/dto/extend-tool-permission.dto");
12
+ /**
13
+ * `POST /api/copilot/runs/:runId/permission` — the answer to a parked run.
14
+ *
15
+ * **A second request against a run that is still streaming**, which is the only
16
+ * shape available: the run is an SSE response, and a response cannot be asked
17
+ * questions. The run yields a `tool-permission-request` carrying its `runId`
18
+ * and the call id, and this route resolves the promise it is awaiting.
19
+ *
20
+ * It intentionally does **not** re-check whether the caller may use the tool.
21
+ * That is not a gap: the offer filtered it, and `executeTool` re-authorizes
22
+ * against freshly resolved grants immediately after this returns. What this
23
+ * route decides is whether the user *wants* the call to happen, which is a
24
+ * different question from whether they are allowed to make it — and answering
25
+ * "yes" to a tool their role has since lost still ends in a refusal downstream.
26
+ *
27
+ * It very much **does** check whose run it is, and the guards above cannot do
28
+ * it for us. `copilot:use` is held by every role including viewers, and
29
+ * `WorkspaceGuard` proves the caller belongs to *the workspace they named* —
30
+ * neither says anything about the run. Without the owner check a colleague
31
+ * could allow (or refuse) a write in someone else's chat, and a member of an
32
+ * unrelated workspace could do it by naming their own: the `runId` is not a
33
+ * secret, it is handed to the client in the `run-started` frame.
34
+ *
35
+ * The 404 is load-bearing rather than cosmetic, and it is deliberately the same
36
+ * answer for "nothing is waiting" and "not yours". Nothing waiting means the
37
+ * decision arrived after the timeout, or the run is parked on another instance
38
+ * (the broker is in-memory — see its notes). Both are worth telling the client
39
+ * about, because in both cases the answer it just gave had no effect — and
40
+ * whether someone else's run exists is not information this route hands out.
41
+ */
42
+ let ToolPermissionController = class ToolPermissionController {
43
+ broker;
44
+ constructor(broker) {
45
+ this.broker = broker;
46
+ }
47
+ decide(runId, body, user, workspaceId) {
48
+ const delivered = this.broker.decide(runId, body.callId, body.decision, {
49
+ userId: user.id,
50
+ workspaceId
51
+ });
52
+ if (!delivered) {
53
+ throw new common_1.NotFoundException('That request is no longer waiting for an answer.');
54
+ }
55
+ }
56
+ /**
57
+ * `POST /api/copilot/runs/:runId/permission/extend` — "I need more time".
58
+ *
59
+ * The prompt used to have a five-minute limit with no warning, no countdown
60
+ * and no way to ask for longer: it simply disappeared, and the model
61
+ * reported that nobody had answered. WCAG 2.2.1 requires that a time limit
62
+ * set by the content can be turned off, adjusted, or **extended after a
63
+ * warning** — and none of its exceptions apply here, since
64
+ * [ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)
65
+ * justifies the limit as cost, not correctness (`ORT-118`).
66
+ *
67
+ * Same guards, same ownership check and same 404 as {@link decide}: this
68
+ * grants time on a parked run, so who may ask is exactly who may answer.
69
+ */
70
+ extend(runId, body, user, workspaceId) {
71
+ const grantedMs = this.broker.extend(runId, body.callId, {
72
+ userId: user.id,
73
+ workspaceId
74
+ });
75
+ if (grantedMs === null) {
76
+ throw new common_1.NotFoundException('That request is no longer waiting for an answer.');
77
+ }
78
+ return { expiresAt: new Date(Date.now() + grantedMs).toISOString() };
79
+ }
80
+ };
81
+ exports.ToolPermissionController = ToolPermissionController;
82
+ tslib_1.__decorate([
83
+ (0, common_1.Post)('runs/:runId/permission'),
84
+ (0, common_1.HttpCode)(204),
85
+ (0, common_1.UseGuards)(identity_server_1.OriginGuard),
86
+ (0, swagger_1.ApiOperation)({
87
+ summary: 'Allow or refuse one tool call in a running turn'
88
+ }),
89
+ tslib_1.__param(0, (0, common_1.Param)('runId', common_1.ParseUUIDPipe)),
90
+ tslib_1.__param(1, (0, common_1.Body)()),
91
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
92
+ tslib_1.__param(3, (0, workspaces_server_1.CurrentWorkspace)()),
93
+ tslib_1.__metadata("design:type", Function),
94
+ tslib_1.__metadata("design:paramtypes", [String, decide_tool_permission_dto_1.DecideToolPermissionDto, Object, String]),
95
+ tslib_1.__metadata("design:returntype", void 0)
96
+ ], ToolPermissionController.prototype, "decide", null);
97
+ tslib_1.__decorate([
98
+ (0, common_1.Post)('runs/:runId/permission/extend'),
99
+ (0, common_1.UseGuards)(identity_server_1.OriginGuard),
100
+ (0, swagger_1.ApiOperation)({
101
+ summary: 'Give the user more time to answer a parked tool call'
102
+ }),
103
+ tslib_1.__param(0, (0, common_1.Param)('runId', common_1.ParseUUIDPipe)),
104
+ tslib_1.__param(1, (0, common_1.Body)()),
105
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
106
+ tslib_1.__param(3, (0, workspaces_server_1.CurrentWorkspace)()),
107
+ tslib_1.__metadata("design:type", Function),
108
+ tslib_1.__metadata("design:paramtypes", [String, extend_tool_permission_dto_1.ExtendToolPermissionDto, Object, String]),
109
+ tslib_1.__metadata("design:returntype", Object)
110
+ ], ToolPermissionController.prototype, "extend", null);
111
+ exports.ToolPermissionController = ToolPermissionController = tslib_1.__decorate([
112
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard, workspaces_server_1.WorkspaceGuard),
113
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.COPILOT_USE),
114
+ (0, common_1.Controller)('copilot'),
115
+ tslib_1.__metadata("design:paramtypes", [tool_permission_broker_1.ToolPermissionBroker])
116
+ ], ToolPermissionController);
@@ -0,0 +1,37 @@
1
+ import { type ModelRegistry } from '@orthacms/copilot-domain';
2
+ import { type PublicUser } from '@orthacms/identity-server';
3
+ import { ConversationRepository, type ConversationView } from '../../infrastructure/persistence/conversation.repository';
4
+ import { UpdateConversationDto } from '../../application/dto/update-conversation.dto';
5
+ /**
6
+ * `PATCH /api/copilot/conversations/:id` — rename a thread, file it away, bring
7
+ * it back, or record the model picked for it.
8
+ *
9
+ * **Archiving is the only removal this API offers, and it is reversible.** A
10
+ * thread's proposals are the receipts for changes that were actually made to
11
+ * the caller's content (ADR-0009), so deleting a conversation would take the
12
+ * only record of those edits with it. Hiding it from the list is the part
13
+ * people want; destroying the audit trail is not, and if a hard delete is ever
14
+ * added it needs to answer for the proposals first.
15
+ *
16
+ * A thread the caller doesn't own is a **404, not a 403** — the repository
17
+ * filters on user and workspace and reports "not found" either way, so an id
18
+ * cannot be probed for existence. `OriginGuard` because this changes state.
19
+ */
20
+ export declare class UpdateConversationController {
21
+ private readonly conversations;
22
+ private readonly models;
23
+ constructor(conversations: ConversationRepository, models: ModelRegistry);
24
+ update(id: string, body: UpdateConversationDto, user: PublicUser, workspaceId: string): Promise<ConversationView>;
25
+ /**
26
+ * Refuses a choice that names no registered backend.
27
+ *
28
+ * The column is read back into the picker and offered as the next run's
29
+ * `provider`/`model`, so an unchecked string is a value the user writes and
30
+ * the UI then renders — and a run that would fail on a backend that does not
31
+ * exist. Checking against `catalogue()` keeps the stored value inside what
32
+ * the operator configured at boot, which is the same boundary the run route
33
+ * enforces when a request names a provider.
34
+ */
35
+ private assertKnownModel;
36
+ }
37
+ //# sourceMappingURL=update-conversation.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-conversation.controller.d.ts","sourceRoot":"","sources":["../../../../../src/lib/chat/http/controllers/update-conversation.controller.ts"],"names":[],"mappings":"AAYA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAMH,KAAK,UAAU,EAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,sBAAsB,EACtB,KAAK,gBAAgB,EACxB,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAEH,qBAAqB,EACxB,MAAM,+CAA+C,CAAC;AAEvD;;;;;;;;;;;;;;GAcG;AACH,qBAGa,4BAA4B;IAEjC,OAAO,CAAC,QAAQ,CAAC,aAAa;IACN,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAD9B,aAAa,EAAE,sBAAsB,EACb,MAAM,EAAE,aAAa;IAQ5D,MAAM,CACoB,EAAE,EAAE,MAAM,EAC9B,IAAI,EAAE,qBAAqB,EACpB,IAAI,EAAE,UAAU,EACX,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,gBAAgB,CAAC;IAuC5B;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;CAoB3B"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UpdateConversationController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const copilot_domain_1 = require("@orthacms/copilot-domain");
8
+ const identity_server_1 = require("@orthacms/identity-server");
9
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
10
+ const conversation_repository_1 = require("../../infrastructure/persistence/conversation.repository");
11
+ const update_conversation_dto_1 = require("../../application/dto/update-conversation.dto");
12
+ /**
13
+ * `PATCH /api/copilot/conversations/:id` — rename a thread, file it away, bring
14
+ * it back, or record the model picked for it.
15
+ *
16
+ * **Archiving is the only removal this API offers, and it is reversible.** A
17
+ * thread's proposals are the receipts for changes that were actually made to
18
+ * the caller's content (ADR-0009), so deleting a conversation would take the
19
+ * only record of those edits with it. Hiding it from the list is the part
20
+ * people want; destroying the audit trail is not, and if a hard delete is ever
21
+ * added it needs to answer for the proposals first.
22
+ *
23
+ * A thread the caller doesn't own is a **404, not a 403** — the repository
24
+ * filters on user and workspace and reports "not found" either way, so an id
25
+ * cannot be probed for existence. `OriginGuard` because this changes state.
26
+ */
27
+ let UpdateConversationController = class UpdateConversationController {
28
+ conversations;
29
+ models;
30
+ constructor(conversations, models) {
31
+ this.conversations = conversations;
32
+ this.models = models;
33
+ }
34
+ async update(id, body, user, workspaceId) {
35
+ // An empty patch cannot mean anything, and answering 200 to it would
36
+ // report success for a write that never happened. The pipe cannot catch
37
+ // this: every property is legitimately optional on its own.
38
+ if (body.title === undefined &&
39
+ body.archived === undefined &&
40
+ body.modelChoice === undefined) {
41
+ throw new common_1.BadRequestException('Provide a title, an archived flag, a model choice, or several.');
42
+ }
43
+ if (body.modelChoice !== undefined) {
44
+ this.assertKnownModel(body.modelChoice);
45
+ }
46
+ const updated = await this.conversations.update(id, user.id, workspaceId, {
47
+ ...(body.title !== undefined ? { title: body.title } : {}),
48
+ ...(body.archived !== undefined
49
+ ? { archived: body.archived }
50
+ : {}),
51
+ ...(body.modelChoice !== undefined
52
+ ? { modelChoice: body.modelChoice }
53
+ : {})
54
+ });
55
+ if (!updated) {
56
+ throw new common_1.NotFoundException('Conversation not found.');
57
+ }
58
+ return updated;
59
+ }
60
+ /**
61
+ * Refuses a choice that names no registered backend.
62
+ *
63
+ * The column is read back into the picker and offered as the next run's
64
+ * `provider`/`model`, so an unchecked string is a value the user writes and
65
+ * the UI then renders — and a run that would fail on a backend that does not
66
+ * exist. Checking against `catalogue()` keeps the stored value inside what
67
+ * the operator configured at boot, which is the same boundary the run route
68
+ * enforces when a request names a provider.
69
+ */
70
+ assertKnownModel(choice) {
71
+ if (choice === update_conversation_dto_1.MODEL_CHOICE_DEFAULT) {
72
+ return;
73
+ }
74
+ // The first colon only: a provider name cannot contain one, and a model
75
+ // id routinely does (`llama3.1:8b`).
76
+ const separator = choice.indexOf(':');
77
+ const provider = separator > 0 ? choice.slice(0, separator) : '';
78
+ const model = separator > 0 ? choice.slice(separator + 1) : '';
79
+ const known = this.models
80
+ .catalogue()
81
+ .some((entry) => entry.provider === provider && entry.model === model);
82
+ if (!known) {
83
+ throw new common_1.BadRequestException('That model choice names no registered backend.');
84
+ }
85
+ }
86
+ };
87
+ exports.UpdateConversationController = UpdateConversationController;
88
+ tslib_1.__decorate([
89
+ (0, common_1.Patch)('conversations/:id'),
90
+ (0, common_1.UseGuards)(identity_server_1.OriginGuard),
91
+ (0, swagger_1.ApiOperation)({
92
+ summary: 'Rename, archive, or set the model of a copilot conversation'
93
+ }),
94
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
95
+ tslib_1.__param(1, (0, common_1.Body)()),
96
+ tslib_1.__param(2, (0, identity_server_1.CurrentUser)()),
97
+ tslib_1.__param(3, (0, workspaces_server_1.CurrentWorkspace)()),
98
+ tslib_1.__metadata("design:type", Function),
99
+ tslib_1.__metadata("design:paramtypes", [String, update_conversation_dto_1.UpdateConversationDto, Object, String]),
100
+ tslib_1.__metadata("design:returntype", Promise)
101
+ ], UpdateConversationController.prototype, "update", null);
102
+ exports.UpdateConversationController = UpdateConversationController = tslib_1.__decorate([
103
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard, workspaces_server_1.WorkspaceGuard),
104
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.COPILOT_USE),
105
+ (0, common_1.Controller)('copilot'),
106
+ tslib_1.__param(1, (0, common_1.Inject)(copilot_domain_1.MODEL_REGISTRY)),
107
+ tslib_1.__metadata("design:paramtypes", [conversation_repository_1.ConversationRepository, Object])
108
+ ], UpdateConversationController);