@mastra/factory 0.24.0-alpha.9 → 0.25.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -13
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +18 -4
- package/dist/auth.js.map +1 -1
- package/dist/boards/review.d.ts.map +1 -1
- package/dist/boards/review.js +3 -2
- package/dist/boards/review.js.map +1 -1
- package/dist/environment/build-runner.js +2 -1
- package/dist/environment/build-runner.js.map +1 -1
- package/dist/environment/build-workflow.js +1 -1
- package/dist/environment/build-workflow.js.map +1 -1
- package/dist/environment/build.js +16 -14
- package/dist/environment/build.js.map +1 -1
- package/dist/factory.d.ts +3 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +172 -88
- package/dist/factory.js.map +1 -1
- package/dist/integrations/base.d.ts +15 -2
- package/dist/integrations/base.d.ts.map +1 -1
- package/dist/integrations/github/app-identity.js.map +1 -1
- package/dist/integrations/github/integration.js +1 -1
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/reconcile-worker.js +1 -1
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/routes.d.ts +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +24 -13
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +53 -9
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.js +2 -2
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
- package/dist/integrations/github/session-subscriptions.js +1 -2
- package/dist/integrations/github/session-subscriptions.js.map +1 -1
- package/dist/integrations/github/subscriptions.d.ts +7 -4
- package/dist/integrations/github/subscriptions.d.ts.map +1 -1
- package/dist/integrations/github/subscriptions.js +5 -5
- package/dist/integrations/github/subscriptions.js.map +1 -1
- package/dist/integrations/gitlab/api.js.map +1 -1
- package/dist/integrations/gitlab/integration.js.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.js +2 -1
- package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
- package/dist/integrations/gitlab/routes.d.ts.map +1 -1
- package/dist/integrations/gitlab/routes.js +10 -6
- package/dist/integrations/gitlab/routes.js.map +1 -1
- package/dist/integrations/gitlab/rules.js.map +1 -1
- package/dist/integrations/gitlab/session-subscriptions.d.ts.map +1 -1
- package/dist/integrations/gitlab/session-subscriptions.js +1 -2
- package/dist/integrations/gitlab/session-subscriptions.js.map +1 -1
- package/dist/integrations/gitlab/subscriptions.d.ts +7 -4
- package/dist/integrations/gitlab/subscriptions.d.ts.map +1 -1
- package/dist/integrations/gitlab/subscriptions.js +5 -5
- package/dist/integrations/gitlab/subscriptions.js.map +1 -1
- package/dist/integrations/incidentio/api.js.map +1 -1
- package/dist/integrations/incidentio/integration.js.map +1 -1
- package/dist/integrations/incidentio/rules.js.map +1 -1
- package/dist/integrations/issue-reconcile-worker.js +1 -1
- package/dist/integrations/issue-reconcile-worker.js.map +1 -1
- package/dist/integrations/issue-reconciler.js +1 -1
- package/dist/integrations/issue-reconciler.js.map +1 -1
- package/dist/integrations/jira/api.js.map +1 -1
- package/dist/integrations/jira/integration.js.map +1 -1
- package/dist/integrations/jira/rules.js.map +1 -1
- package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
- package/dist/integrations/linear/agent-tools.js.map +1 -1
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/platform/api-client.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +1 -1
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.js +2 -2
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/gitlab/event-worker.js.map +1 -1
- package/dist/integrations/platform/gitlab/integration.js.map +1 -1
- package/dist/integrations/platform/incidentio/integration.js +2 -1
- package/dist/integrations/platform/incidentio/integration.js.map +1 -1
- package/dist/integrations/platform/jira/integration.js.map +1 -1
- package/dist/integrations/platform/linear/event-worker.js +1 -1
- package/dist/integrations/platform/linear/event-worker.js.map +1 -1
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/{session → integrations/slack}/channel-reply-processor.d.ts +11 -9
- package/dist/integrations/slack/channel-reply-processor.d.ts.map +1 -0
- package/dist/integrations/slack/channel-reply-processor.js +61 -0
- package/dist/integrations/slack/channel-reply-processor.js.map +1 -0
- package/dist/integrations/slack/channel-session-link-processor.d.ts.map +1 -0
- package/dist/{session → integrations/slack}/channel-session-link-processor.js +14 -4
- package/dist/integrations/slack/channel-session-link-processor.js.map +1 -0
- package/dist/integrations/slack/connect-route.js +1 -1
- package/dist/integrations/slack/connect-route.js.map +1 -1
- package/dist/integrations/slack/feed-publisher.js +1 -1
- package/dist/integrations/slack/feed-publisher.js.map +1 -1
- package/dist/integrations/slack/integration.d.ts +25 -1
- package/dist/integrations/slack/integration.d.ts.map +1 -1
- package/dist/integrations/slack/integration.js +56 -6
- package/dist/integrations/slack/integration.js.map +1 -1
- package/dist/integrations/slack/reply-reminder-processor.d.ts +23 -0
- package/dist/integrations/slack/reply-reminder-processor.d.ts.map +1 -0
- package/dist/integrations/slack/reply-reminder-processor.js +58 -0
- package/dist/integrations/slack/reply-reminder-processor.js.map +1 -0
- package/dist/integrations/slack/reply-tool.d.ts +31 -0
- package/dist/integrations/slack/reply-tool.d.ts.map +1 -0
- package/dist/integrations/slack/reply-tool.js +203 -0
- package/dist/integrations/slack/reply-tool.js.map +1 -0
- package/dist/integrations/slack/share-file-tool.d.ts +45 -0
- package/dist/integrations/slack/share-file-tool.d.ts.map +1 -0
- package/dist/integrations/slack/share-file-tool.js +106 -0
- package/dist/integrations/slack/share-file-tool.js.map +1 -0
- package/dist/integrations/slack/slack.d.ts +16 -5
- package/dist/integrations/slack/slack.d.ts.map +1 -1
- package/dist/integrations/slack/slack.js +141 -40
- package/dist/integrations/slack/slack.js.map +1 -1
- package/dist/integrations/subscription-session.d.ts +0 -1
- package/dist/integrations/subscription-session.d.ts.map +1 -1
- package/dist/integrations/subscription-session.js +1 -4
- package/dist/integrations/subscription-session.js.map +1 -1
- package/dist/integrations/workos/integration.js.map +1 -1
- package/dist/mcp/events.d.ts +73 -0
- package/dist/mcp/events.d.ts.map +1 -0
- package/dist/mcp/events.js +158 -0
- package/dist/mcp/events.js.map +1 -0
- package/dist/mcp/routes.d.ts +0 -1
- package/dist/mcp/routes.d.ts.map +1 -1
- package/dist/mcp/routes.js +31 -4
- package/dist/mcp/routes.js.map +1 -1
- package/dist/packages/_internals/workspace/dist/index.js +18 -1
- package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
- package/dist/platform-auth-host.d.ts.map +1 -1
- package/dist/platform-auth-host.js +1 -1
- package/dist/platform-auth-host.js.map +1 -1
- package/dist/routes/attention-activity.js.map +1 -1
- package/dist/routes/attention-parked.js.map +1 -1
- package/dist/routes/attention-providers.js.map +1 -1
- package/dist/routes/automation-runs.js.map +1 -1
- package/dist/routes/config.d.ts +8 -7
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +70 -28
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/contracts.d.ts +2 -0
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/contracts.js +2 -2
- package/dist/routes/contracts.js.map +1 -1
- package/dist/routes/custom-provider-source.js.map +1 -1
- package/dist/routes/fs.d.ts +31 -23
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +218 -64
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/intake.js +2 -1
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/knowledge.js +1 -1
- package/dist/routes/knowledge.js.map +1 -1
- package/dist/routes/oauth.js +3 -2
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/projects.d.ts +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +33 -31
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/provider-credentials.d.ts.map +1 -1
- package/dist/routes/provider-credentials.js +6 -1
- package/dist/routes/provider-credentials.js.map +1 -1
- package/dist/routes/session-access.d.ts +60 -0
- package/dist/routes/session-access.d.ts.map +1 -0
- package/dist/routes/session-access.js +202 -0
- package/dist/routes/session-access.js.map +1 -0
- package/dist/routes/skills.d.ts +2 -4
- package/dist/routes/skills.d.ts.map +1 -1
- package/dist/routes/skills.js +23 -68
- package/dist/routes/skills.js.map +1 -1
- package/dist/routes/source-control-sessions.d.ts +8 -1
- package/dist/routes/source-control-sessions.d.ts.map +1 -1
- package/dist/routes/source-control-sessions.js +239 -19
- package/dist/routes/source-control-sessions.js.map +1 -1
- package/dist/routes/surface.d.ts +7 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +20 -8
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/tenant-credentials.js.map +1 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/binding-context.js +11 -9
- package/dist/rules/binding-context.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +1 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +21 -13
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts +2 -2
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +3 -3
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/start-coordinator.d.ts +4 -0
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +36 -4
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/tools.js +2 -2
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/sandbox/callback-factory-sandbox.js.map +1 -1
- package/dist/sandbox/local-factory-sandbox.js.map +1 -1
- package/dist/sandbox/session-retirement.d.ts +11 -0
- package/dist/sandbox/session-retirement.d.ts.map +1 -1
- package/dist/sandbox/session-retirement.js +38 -1
- package/dist/sandbox/session-retirement.js.map +1 -1
- package/dist/sandbox/session-sandbox.d.ts +2 -0
- package/dist/sandbox/session-sandbox.d.ts.map +1 -1
- package/dist/sandbox/session-sandbox.js +5 -1
- package/dist/sandbox/session-sandbox.js.map +1 -1
- package/dist/secret-encryption.d.ts.map +1 -1
- package/dist/secret-encryption.js +65 -25
- package/dist/secret-encryption.js.map +1 -1
- package/dist/session/credential-policy.d.ts +4 -2
- package/dist/session/credential-policy.d.ts.map +1 -1
- package/dist/session/credential-policy.js +18 -7
- package/dist/session/credential-policy.js.map +1 -1
- package/dist/session/default-model-hydration.d.ts +1 -0
- package/dist/session/default-model-hydration.d.ts.map +1 -1
- package/dist/session/default-model-hydration.js +3 -2
- package/dist/session/default-model-hydration.js.map +1 -1
- package/dist/session/environment-state-processor.js +1 -1
- package/dist/session/environment-state-processor.js.map +1 -1
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +14 -1
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/filesystem-capture.d.ts +3 -3
- package/dist/session/filesystem-capture.d.ts.map +1 -1
- package/dist/session/filesystem-capture.js +16 -17
- package/dist/session/filesystem-capture.js.map +1 -1
- package/dist/session/first-exec-capture.d.ts +1 -1
- package/dist/session/first-exec-capture.d.ts.map +1 -1
- package/dist/session/first-exec-capture.js +1 -1
- package/dist/session/first-exec-capture.js.map +1 -1
- package/dist/session/first-message-capture.d.ts +1 -1
- package/dist/session/first-message-capture.d.ts.map +1 -1
- package/dist/session/first-message-capture.js +1 -1
- package/dist/session/first-message-capture.js.map +1 -1
- package/dist/session/live-sessions.d.ts +1 -1
- package/dist/session/live-sessions.js +1 -1
- package/dist/session/live-sessions.js.map +1 -1
- package/dist/session/memory-settings-hydration.d.ts +1 -1
- package/dist/session/memory-settings-hydration.d.ts.map +1 -1
- package/dist/session/memory-settings-hydration.js +2 -1
- package/dist/session/memory-settings-hydration.js.map +1 -1
- package/dist/session/resource-migration.d.ts +105 -0
- package/dist/session/resource-migration.d.ts.map +1 -0
- package/dist/session/resource-migration.js +195 -0
- package/dist/session/resource-migration.js.map +1 -0
- package/dist/session/run-audit.d.ts +1 -0
- package/dist/session/run-audit.d.ts.map +1 -1
- package/dist/session/run-audit.js +7 -2
- package/dist/session/run-audit.js.map +1 -1
- package/dist/session/session-threads.d.ts +63 -0
- package/dist/session/session-threads.d.ts.map +1 -0
- package/dist/session/session-threads.js +97 -0
- package/dist/session/session-threads.js.map +1 -0
- package/dist/session/source-control-tools.js +8 -8
- package/dist/session/source-control-tools.js.map +1 -1
- package/dist/session/thinking-default.d.ts +6 -13
- package/dist/session/thinking-default.d.ts.map +1 -1
- package/dist/session/thinking-default.js +19 -24
- package/dist/session/thinking-default.js.map +1 -1
- package/dist/session/thread-session-stamp.d.ts +21 -0
- package/dist/session/thread-session-stamp.d.ts.map +1 -0
- package/dist/session/thread-session-stamp.js +20 -0
- package/dist/session/thread-session-stamp.js.map +1 -0
- package/dist/session/thread-title-mirror.d.ts +1 -1
- package/dist/session/thread-title-mirror.d.ts.map +1 -1
- package/dist/session/thread-title-mirror.js +1 -1
- package/dist/session/thread-title-mirror.js.map +1 -1
- package/dist/session-owner-signal.d.ts +2 -0
- package/dist/session-owner-signal.d.ts.map +1 -0
- package/dist/session-owner-signal.js +6 -0
- package/dist/session-owner-signal.js.map +1 -0
- package/dist/skills/service.d.ts +11 -14
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/skills/service.js +12 -22
- package/dist/skills/service.js.map +1 -1
- package/dist/spa-static.js.map +1 -1
- package/dist/state-signing.js +1 -1
- package/dist/state-signing.js.map +1 -1
- package/dist/storage/domains/audit/actions.d.ts +1 -0
- package/dist/storage/domains/audit/actions.d.ts.map +1 -1
- package/dist/storage/domains/audit/actions.js +2 -1
- package/dist/storage/domains/audit/actions.js.map +1 -1
- package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -1
- package/dist/storage/domains/audit/agent-audit.js +2 -2
- package/dist/storage/domains/audit/agent-audit.js.map +1 -1
- package/dist/storage/domains/audit/base.d.ts +18 -2
- package/dist/storage/domains/audit/base.d.ts.map +1 -1
- package/dist/storage/domains/audit/base.js +22 -4
- package/dist/storage/domains/audit/base.js.map +1 -1
- package/dist/storage/domains/audit/domain.js.map +1 -1
- package/dist/storage/domains/channel-identity/base.js.map +1 -1
- package/dist/storage/domains/comments/base.js.map +1 -1
- package/dist/storage/domains/comments/domain.js.map +1 -1
- package/dist/storage/domains/comments/feed-context.js.map +1 -1
- package/dist/storage/domains/credentials/base.js.map +1 -1
- package/dist/storage/domains/custom-providers/base.js.map +1 -1
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts +8 -0
- package/dist/storage/domains/integrations/base.d.ts.map +1 -1
- package/dist/storage/domains/integrations/base.js +7 -0
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/memory-settings/base.js.map +1 -1
- package/dist/storage/domains/model-defaults/base.d.ts +8 -0
- package/dist/storage/domains/model-defaults/base.d.ts.map +1 -1
- package/dist/storage/domains/model-defaults/base.js +18 -0
- package/dist/storage/domains/model-defaults/base.js.map +1 -1
- package/dist/storage/domains/projects/base.js.map +1 -1
- package/dist/storage/domains/queue-health/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +44 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +109 -3
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +23 -1
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +35 -0
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +14 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +25 -1
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/storage/domains/work-items/board-version.js.map +1 -1
- package/dist/storage/domains/work-items/metrics.js.map +1 -1
- package/dist/tools/approval-tools.js +1 -1
- package/dist/tools/approval-tools.js.map +1 -1
- package/dist/tools/deliver.d.ts +8 -5
- package/dist/tools/deliver.d.ts.map +1 -1
- package/dist/tools/deliver.js +22 -8
- package/dist/tools/deliver.js.map +1 -1
- package/dist/tools/messaging-tools.d.ts +1 -1
- package/dist/tools/messaging-tools.d.ts.map +1 -1
- package/dist/tools/messaging-tools.js +203 -72
- package/dist/tools/messaging-tools.js.map +1 -1
- package/dist/tools/permissions.d.ts +1 -1
- package/dist/tools/permissions.d.ts.map +1 -1
- package/dist/tools/permissions.js +3 -2
- package/dist/tools/permissions.js.map +1 -1
- package/dist/tools/reports.d.ts.map +1 -1
- package/dist/tools/reports.js +10 -3
- package/dist/tools/reports.js.map +1 -1
- package/dist/tools/run-watch.d.ts +2 -0
- package/dist/tools/run-watch.d.ts.map +1 -1
- package/dist/tools/run-watch.js +42 -2
- package/dist/tools/run-watch.js.map +1 -1
- package/dist/tools/sandbox-tools.d.ts +12 -0
- package/dist/tools/sandbox-tools.d.ts.map +1 -0
- package/dist/tools/sandbox-tools.js +40 -0
- package/dist/tools/sandbox-tools.js.map +1 -0
- package/dist/tools/scope.d.ts +2 -1
- package/dist/tools/scope.d.ts.map +1 -1
- package/dist/tools/scope.js +5 -7
- package/dist/tools/scope.js.map +1 -1
- package/dist/tools/session-tools.d.ts +1 -1
- package/dist/tools/session-tools.d.ts.map +1 -1
- package/dist/tools/session-tools.js +39 -18
- package/dist/tools/session-tools.js.map +1 -1
- package/dist/tools/sessions-state-processor.js +2 -2
- package/dist/tools/sessions-state-processor.js.map +1 -1
- package/dist/tools/side-sessions.d.ts +1 -1
- package/dist/tools/side-sessions.d.ts.map +1 -1
- package/dist/tools/side-sessions.js +1 -1
- package/dist/tools/side-sessions.js.map +1 -1
- package/dist/work-item-branch.d.ts +11 -3
- package/dist/work-item-branch.d.ts.map +1 -1
- package/dist/work-item-branch.js +34 -9
- package/dist/work-item-branch.js.map +1 -1
- package/dist/workspace.d.ts +7 -3
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +32 -17
- package/dist/workspace.js.map +1 -1
- package/factory-skills/configure-factory-rules/SKILL.md +2 -2
- package/package.json +16 -15
- package/dist/session/channel-reply-processor.d.ts.map +0 -1
- package/dist/session/channel-reply-processor.js +0 -46
- package/dist/session/channel-reply-processor.js.map +0 -1
- package/dist/session/channel-session-link-processor.d.ts.map +0 -1
- package/dist/session/channel-session-link-processor.js.map +0 -1
- /package/dist/{session → integrations/slack}/channel-session-link-processor.d.ts +0 -0
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import { isValidGitRef } from "../sandbox/git-ref.js";
|
|
2
|
+
import { canReadSessionResource, canSwitchSessionModel, canViewSourceControlSession } from "./session-access.js";
|
|
2
3
|
import { waitForPendingFilesystemCapture } from "../session/filesystem-capture.js";
|
|
4
|
+
import { isRunBound, isWorkerSession, listFactorySessionThreads, sessionMemoryResourceId, sessionThreadsToMove, userSessionResourceFor } from "../session/session-threads.js";
|
|
3
5
|
import { normalizeSessionTitle } from "../session/session-title.js";
|
|
4
6
|
import { reclaimDeletedSessionSandbox } from "../integrations/github/sandbox-release.js";
|
|
5
7
|
import { seedSessionOrg } from "../session/org-seed.js";
|
|
8
|
+
import { SESSION_OWNER_SIGNAL_TAG } from "../session-owner-signal.js";
|
|
6
9
|
import { RequestContext } from "@mastra/core/request-context";
|
|
7
10
|
import { registerApiRoute } from "@mastra/core/server";
|
|
8
11
|
import { UniqueViolationError } from "@mastra/core/storage";
|
|
9
12
|
import { resolveModel } from "@mastra/code-sdk/agents/model";
|
|
13
|
+
import { createSignal } from "@mastra/core/signals";
|
|
10
14
|
//#region src/routes/source-control-sessions.ts
|
|
11
15
|
function loose(c) {
|
|
12
16
|
return c;
|
|
13
17
|
}
|
|
14
18
|
const USER_SESSION_BRANCH_PREFIX = "user/session-";
|
|
19
|
+
const SLACK_SESSION_BRANCH_PREFIX = "slack/";
|
|
15
20
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
16
21
|
const MAX_SESSION_OWNER_PROFILES = 100;
|
|
17
22
|
const MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES = 500;
|
|
18
|
-
const SESSION_OWNER_PROFILE_TTL_MS =
|
|
23
|
+
const SESSION_OWNER_PROFILE_TTL_MS = 3e5;
|
|
19
24
|
const ABORT_SETTLE_TIMEOUT_MS = 5e3;
|
|
20
25
|
const ABORT_SETTLE_POLL_MS = 50;
|
|
21
26
|
/**
|
|
@@ -33,25 +38,58 @@ async function sessionManagePermission(c, auth, tenant, session) {
|
|
|
33
38
|
function canRecreateSandbox(options) {
|
|
34
39
|
return Boolean(options.sessionRetirement) && options.sandboxRecreateSupported === true;
|
|
35
40
|
}
|
|
36
|
-
function withCapabilities(session,
|
|
41
|
+
function withCapabilities(session, capabilities) {
|
|
37
42
|
return {
|
|
38
43
|
...session,
|
|
39
|
-
capabilities
|
|
44
|
+
capabilities
|
|
40
45
|
};
|
|
41
46
|
}
|
|
47
|
+
async function ownershipRefusal(session, options) {
|
|
48
|
+
if (!session.factoryProjectId) return {
|
|
49
|
+
status: 409,
|
|
50
|
+
error: "This session isn't linked to a Factory, so it can't change owner."
|
|
51
|
+
};
|
|
52
|
+
if (!options.workItems) return {
|
|
53
|
+
status: 503,
|
|
54
|
+
error: "Session ownership can't change yet: Factory storage is still starting up. Try again in a moment."
|
|
55
|
+
};
|
|
56
|
+
if (session.branch.startsWith(SLACK_SESSION_BRANCH_PREFIX) || await isWorkerSession(session, options.workItems)) return {
|
|
57
|
+
status: 409,
|
|
58
|
+
error: "Only user sessions can change owner"
|
|
59
|
+
};
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
/** Marks the takeover in every thread of the session: the transcript draws it as a divider and the model reads it as context. */
|
|
63
|
+
async function markOwnerChange(options, session, newOwner) {
|
|
64
|
+
const { controller } = options;
|
|
65
|
+
const memory = await controller?.getMastra()?.getStorage()?.getStore("memory");
|
|
66
|
+
if (!controller || !memory) return;
|
|
67
|
+
const threads = await listFactorySessionThreads(controller, session, options.workItems);
|
|
68
|
+
if (threads.length === 0) return;
|
|
69
|
+
const contents = `${newOwner.name ?? "A teammate"} took ownership`;
|
|
70
|
+
await memory.saveMessages({ messages: threads.map((thread) => createSignal({
|
|
71
|
+
type: "reactive",
|
|
72
|
+
tagName: SESSION_OWNER_SIGNAL_TAG,
|
|
73
|
+
contents,
|
|
74
|
+
author: newOwner
|
|
75
|
+
}).toDBMessage({
|
|
76
|
+
threadId: thread.id,
|
|
77
|
+
resourceId: thread.resourceId
|
|
78
|
+
})) });
|
|
79
|
+
}
|
|
42
80
|
/** Abort the session's active run and wait (bounded) for it to stop. Returns whether a run was aborted. */
|
|
43
81
|
async function abortActiveRun(controller, sessionId, settleTimeoutMs) {
|
|
44
82
|
if (!controller) return false;
|
|
45
83
|
try {
|
|
46
|
-
const live = await controller.
|
|
84
|
+
const live = await controller.getSession(sessionId);
|
|
47
85
|
if (!live?.stream.isActive()) return false;
|
|
48
86
|
live.abort();
|
|
49
87
|
const deadline = Date.now() + settleTimeoutMs;
|
|
50
88
|
while (live.stream.isActive() && Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, ABORT_SETTLE_POLL_MS));
|
|
51
|
-
if (live.stream.isActive()) console.warn("[Factory Sessions] Aborted run did not settle
|
|
89
|
+
if (live.stream.isActive()) console.warn("[Factory Sessions] Aborted run did not settle in time", { sessionId });
|
|
52
90
|
return true;
|
|
53
91
|
} catch (error) {
|
|
54
|
-
console.warn("[Factory Sessions] Failed to abort the active run
|
|
92
|
+
console.warn("[Factory Sessions] Failed to abort the active run", {
|
|
55
93
|
sessionId,
|
|
56
94
|
error
|
|
57
95
|
});
|
|
@@ -109,14 +147,25 @@ async function resolveSession(sourceControls, sessionId) {
|
|
|
109
147
|
if (matches.length > 1) throw new Error("Factory session exists in multiple source-control providers.");
|
|
110
148
|
return matches[0] ?? null;
|
|
111
149
|
}
|
|
150
|
+
async function resolveReadableSession(options, sessionId, viewer) {
|
|
151
|
+
const match = await resolveSession(options.sourceControls, sessionId);
|
|
152
|
+
if (!match || !canViewSourceControlSession(match.session, viewer)) return null;
|
|
153
|
+
const resourceId = await sessionMemoryResourceId(options.controller, match.session, options.workItems);
|
|
154
|
+
if (!canReadSessionResource(match.session, resourceId, viewer)) return null;
|
|
155
|
+
return {
|
|
156
|
+
...match,
|
|
157
|
+
resourceId
|
|
158
|
+
};
|
|
159
|
+
}
|
|
112
160
|
/**
|
|
113
|
-
* Start the live conversation for a user session on its own thread (thread id === session id)
|
|
161
|
+
* Start the live conversation for a user session on its own thread (thread id === session id), under the resource
|
|
162
|
+
* its visibility gives it. Agent-controller
|
|
114
163
|
* routes only act on started sessions, so the first prompt the page sends right after creation always lands on the
|
|
115
164
|
* thread the page reads, with the org and Factory address already in state. Get-or-create, so retried or repeated
|
|
116
165
|
* creates are safe.
|
|
117
166
|
*/
|
|
118
|
-
async function startUserSessionConversation(controller, session) {
|
|
119
|
-
if (!controller) return;
|
|
167
|
+
async function startUserSessionConversation(controller, session, resourceId = userSessionResourceFor(session, session.visibility === "org" ? "org" : "private")) {
|
|
168
|
+
if (!controller) return void 0;
|
|
120
169
|
const requestContext = new RequestContext();
|
|
121
170
|
requestContext.set("user", {
|
|
122
171
|
workosId: session.userId,
|
|
@@ -124,7 +173,7 @@ async function startUserSessionConversation(controller, session) {
|
|
|
124
173
|
});
|
|
125
174
|
const live = await controller.createSession({
|
|
126
175
|
id: session.sessionId,
|
|
127
|
-
resourceId
|
|
176
|
+
resourceId,
|
|
128
177
|
threadId: session.sessionId,
|
|
129
178
|
ownerId: session.userId,
|
|
130
179
|
requestContext
|
|
@@ -134,6 +183,7 @@ async function startUserSessionConversation(controller, session) {
|
|
|
134
183
|
factoryProjectId: session.factoryProjectId,
|
|
135
184
|
...session.projectRepositoryId ? { projectRepositoryId: session.projectRepositoryId } : {}
|
|
136
185
|
});
|
|
186
|
+
return live;
|
|
137
187
|
}
|
|
138
188
|
function isJsonObject(value) {
|
|
139
189
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -148,6 +198,10 @@ function createSessionNaming() {
|
|
|
148
198
|
return started;
|
|
149
199
|
};
|
|
150
200
|
}
|
|
201
|
+
const OWNER_CONFLICT_MESSAGES = {
|
|
202
|
+
stale_owner: "Someone else owns this session now",
|
|
203
|
+
branch_owned: "You already have a session on this branch"
|
|
204
|
+
};
|
|
151
205
|
function titleModel(modelId) {
|
|
152
206
|
return ({ requestContext }) => resolveModel(modelId, {
|
|
153
207
|
remapForCodexOAuth: true,
|
|
@@ -254,6 +308,8 @@ function projectSessionRoutes(path, options, resolveOwnerProfiles) {
|
|
|
254
308
|
const sessionId = requestedSessionId ?? globalThis.crypto.randomUUID();
|
|
255
309
|
if (body.title !== void 0 && typeof body.title !== "string") return c.json({ error: "Invalid title" }, 400);
|
|
256
310
|
const normalizedTitle = body.title === void 0 ? null : normalizeSessionTitle(body.title);
|
|
311
|
+
if (body.visibility !== void 0 && body.visibility !== "private" && body.visibility !== "org") return c.json({ error: "visibility must be 'private' or 'org'" }, 400);
|
|
312
|
+
const visibility = body.visibility ?? "org";
|
|
257
313
|
let branch;
|
|
258
314
|
if (body.branch === void 0) branch = `${USER_SESSION_BRANCH_PREFIX}${sessionId}`;
|
|
259
315
|
else if (isValidGitRef(body.branch)) branch = body.branch;
|
|
@@ -263,7 +319,11 @@ function projectSessionRoutes(path, options, resolveOwnerProfiles) {
|
|
|
263
319
|
if (existing) {
|
|
264
320
|
if (existing.projectRepositoryId !== project.project.id || existing.orgId !== orgId || existing.userId !== userId || existing.branch !== branch) return c.json({ error: "Session ID conflict" }, 409);
|
|
265
321
|
await startUserSessionConversation(options.controller, existing);
|
|
266
|
-
return c.json({ session: withCapabilities(existing,
|
|
322
|
+
return c.json({ session: withCapabilities(existing, {
|
|
323
|
+
recreateSandbox: canRecreateSandbox(options),
|
|
324
|
+
takeOwnership: false,
|
|
325
|
+
switchModel: true
|
|
326
|
+
}) });
|
|
267
327
|
}
|
|
268
328
|
}
|
|
269
329
|
const session = await project.sourceControl.sessions.create({
|
|
@@ -275,7 +335,7 @@ function projectSessionRoutes(path, options, resolveOwnerProfiles) {
|
|
|
275
335
|
branch,
|
|
276
336
|
baseBranch,
|
|
277
337
|
title: normalizedTitle,
|
|
278
|
-
visibility
|
|
338
|
+
visibility
|
|
279
339
|
}).catch(async (error) => {
|
|
280
340
|
if (!(error instanceof UniqueViolationError) || !requestedSessionId) throw error;
|
|
281
341
|
const conflict = await project.sourceControl.sessions.getBySessionId(sessionId);
|
|
@@ -284,7 +344,11 @@ function projectSessionRoutes(path, options, resolveOwnerProfiles) {
|
|
|
284
344
|
});
|
|
285
345
|
if (requestedSessionId && (session.sessionId !== sessionId || session.projectRepositoryId !== project.project.id || session.orgId !== orgId || session.userId !== userId || session.branch !== branch)) return c.json({ error: "Session ID conflict" }, 409);
|
|
286
346
|
await startUserSessionConversation(options.controller, session);
|
|
287
|
-
return c.json({ session: withCapabilities(session,
|
|
347
|
+
return c.json({ session: withCapabilities(session, {
|
|
348
|
+
recreateSandbox: canRecreateSandbox(options),
|
|
349
|
+
takeOwnership: false,
|
|
350
|
+
switchModel: true
|
|
351
|
+
}) });
|
|
288
352
|
}
|
|
289
353
|
})];
|
|
290
354
|
}
|
|
@@ -322,11 +386,47 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
322
386
|
handler: async (c) => {
|
|
323
387
|
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
324
388
|
if ("response" in resolved) return resolved.response;
|
|
325
|
-
const
|
|
326
|
-
if (!
|
|
389
|
+
const readable = await resolveReadableSession(options, c.req.param("sessionId"), resolved.tenant);
|
|
390
|
+
if (!readable) return c.json({ error: "Session not found" }, 404);
|
|
391
|
+
const { session, resourceId } = readable;
|
|
327
392
|
const owners = await resolveOwnerProfiles([session.userId]);
|
|
328
393
|
const recreateSandbox = canRecreateSandbox(options) && await sessionManagePermission(loose(c), options.auth, resolved.tenant, session) === "allowed";
|
|
329
|
-
|
|
394
|
+
const takeOwnership = session.userId !== resolved.tenant.userId && await ownershipRefusal(session, options) === null;
|
|
395
|
+
return c.json({ session: {
|
|
396
|
+
...withCapabilities(withOwnerProfile(session, owners), {
|
|
397
|
+
recreateSandbox,
|
|
398
|
+
takeOwnership,
|
|
399
|
+
switchModel: canSwitchSessionModel(session, resolved.tenant)
|
|
400
|
+
}),
|
|
401
|
+
resourceId
|
|
402
|
+
} });
|
|
403
|
+
}
|
|
404
|
+
}),
|
|
405
|
+
registerApiRoute("/web/user-sessions/:sessionId/sandbox/start", {
|
|
406
|
+
method: "POST",
|
|
407
|
+
requiresAuth: false,
|
|
408
|
+
handler: async (c) => {
|
|
409
|
+
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
410
|
+
if ("response" in resolved) return resolved.response;
|
|
411
|
+
const session = (await resolveSession(options.sourceControls, c.req.param("sessionId")))?.session;
|
|
412
|
+
if (!session) return c.json({ error: "Session not found" }, 404);
|
|
413
|
+
const permission = await sessionManagePermission(loose(c), options.auth, resolved.tenant, session);
|
|
414
|
+
if (permission === "not-found") return c.json({ error: "Session not found" }, 404);
|
|
415
|
+
if (permission === "forbidden") return c.json({ error: "Only the session's owner or an organization admin can start its sandbox." }, 403);
|
|
416
|
+
const controller = options.controller;
|
|
417
|
+
if (!controller) return c.json({ error: "Sessions are not available on this server." }, 503);
|
|
418
|
+
try {
|
|
419
|
+
const sandbox = (await controller.getSession(session.sessionId) ?? await startUserSessionConversation(controller, session, await sessionMemoryResourceId(controller, session, options.workItems)))?.getWorkspace()?.sandbox;
|
|
420
|
+
if (!sandbox?.start) return c.json({ error: "This session has no sandbox to start." }, 409);
|
|
421
|
+
await sandbox.start();
|
|
422
|
+
return c.json({ started: true });
|
|
423
|
+
} catch (error) {
|
|
424
|
+
console.error("[Factory Sessions] Failed to start session sandbox", {
|
|
425
|
+
sessionId: session.sessionId,
|
|
426
|
+
error
|
|
427
|
+
});
|
|
428
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
429
|
+
}
|
|
330
430
|
}
|
|
331
431
|
}),
|
|
332
432
|
registerApiRoute("/web/user-sessions/:sessionId/sandbox/recreate", {
|
|
@@ -375,6 +475,82 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
375
475
|
}
|
|
376
476
|
}
|
|
377
477
|
}),
|
|
478
|
+
registerApiRoute("/web/user-sessions/:sessionId/owner", {
|
|
479
|
+
method: "POST",
|
|
480
|
+
requiresAuth: false,
|
|
481
|
+
handler: async (c) => {
|
|
482
|
+
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
483
|
+
if ("response" in resolved) return resolved.response;
|
|
484
|
+
const { orgId, userId } = resolved.tenant;
|
|
485
|
+
const sessionId = c.req.param("sessionId");
|
|
486
|
+
const readable = await resolveReadableSession(options, sessionId, resolved.tenant);
|
|
487
|
+
if (!readable) return c.json({ error: "Session not found" }, 404);
|
|
488
|
+
const { sourceControl, session } = readable;
|
|
489
|
+
let body;
|
|
490
|
+
try {
|
|
491
|
+
body = await c.req.json();
|
|
492
|
+
} catch {
|
|
493
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
494
|
+
}
|
|
495
|
+
if (!isJsonObject(body) || typeof body.expectedOwnerId !== "string" || !body.expectedOwnerId.trim()) return c.json({ error: "Invalid expectedOwnerId" }, 400);
|
|
496
|
+
const expectedOwnerId = body.expectedOwnerId;
|
|
497
|
+
if (session.userId === userId) return c.json({ session });
|
|
498
|
+
const refusal = await ownershipRefusal(session, options);
|
|
499
|
+
if (refusal) return c.json({ error: refusal.error }, refusal.status);
|
|
500
|
+
const transferred = await sourceControl.sessions.transferOwner({
|
|
501
|
+
sessionId,
|
|
502
|
+
expectedUserId: expectedOwnerId,
|
|
503
|
+
toUserId: userId
|
|
504
|
+
});
|
|
505
|
+
if (transferred.status === "conflict") {
|
|
506
|
+
const current = transferred.session;
|
|
507
|
+
if (!current || !canViewSourceControlSession(current, resolved.tenant)) return c.json({ error: "Session not found" }, 404);
|
|
508
|
+
if (current.userId === userId) return c.json({ session: current });
|
|
509
|
+
return c.json({
|
|
510
|
+
error: OWNER_CONFLICT_MESSAGES[transferred.reason],
|
|
511
|
+
reason: transferred.reason,
|
|
512
|
+
currentOwnerId: current.userId
|
|
513
|
+
}, 409);
|
|
514
|
+
}
|
|
515
|
+
const controller = options.controller;
|
|
516
|
+
await abortActiveRun(controller, sessionId, options.abortSettleTimeoutMs ?? ABORT_SETTLE_TIMEOUT_MS);
|
|
517
|
+
if (controller && await controller.getSession(sessionId)) await controller.deleteSession({ sessionId }).catch((error) => {
|
|
518
|
+
console.error("[Factory Sessions] Failed to recycle transferred live session", {
|
|
519
|
+
sessionId,
|
|
520
|
+
error
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
const newOwner = (await resolveOwnerProfiles([userId])).get(userId) ?? { id: userId };
|
|
524
|
+
await markOwnerChange(options, transferred.session, newOwner).catch((error) => {
|
|
525
|
+
console.error("[Factory Sessions] Failed to mark the ownership change in the transcript", {
|
|
526
|
+
sessionId,
|
|
527
|
+
error
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
await options.audit?.record({
|
|
531
|
+
orgId,
|
|
532
|
+
actorId: userId,
|
|
533
|
+
action: "factory.session.owner_transferred",
|
|
534
|
+
targets: [{
|
|
535
|
+
type: "session",
|
|
536
|
+
id: session.id,
|
|
537
|
+
name: session.title ?? session.branch
|
|
538
|
+
}],
|
|
539
|
+
metadata: {
|
|
540
|
+
fromOwnerId: expectedOwnerId,
|
|
541
|
+
toOwnerId: userId
|
|
542
|
+
},
|
|
543
|
+
factoryProjectId: session.factoryProjectId ?? void 0,
|
|
544
|
+
projectRepositoryId: session.projectRepositoryId ?? void 0
|
|
545
|
+
}).catch((error) => {
|
|
546
|
+
console.error("[Factory Sessions] Failed to record ownership transfer audit event", {
|
|
547
|
+
sessionId,
|
|
548
|
+
error
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
return c.json({ session: transferred.session });
|
|
552
|
+
}
|
|
553
|
+
}),
|
|
378
554
|
registerApiRoute("/web/user-sessions/:sessionId", {
|
|
379
555
|
method: "DELETE",
|
|
380
556
|
requiresAuth: false,
|
|
@@ -391,7 +567,7 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
391
567
|
error
|
|
392
568
|
});
|
|
393
569
|
});
|
|
394
|
-
await options.controller?.deleteSession({
|
|
570
|
+
await options.controller?.deleteSession({ sessionId: session.sessionId });
|
|
395
571
|
} catch (error) {
|
|
396
572
|
console.error("[Factory Sessions] Failed to tear down live controller session", {
|
|
397
573
|
sessionId: session.sessionId,
|
|
@@ -422,6 +598,50 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
422
598
|
return c.json({ removed: true });
|
|
423
599
|
}
|
|
424
600
|
}),
|
|
601
|
+
registerApiRoute("/web/user-sessions/:sessionId/visibility", {
|
|
602
|
+
method: "PUT",
|
|
603
|
+
requiresAuth: false,
|
|
604
|
+
handler: async (c) => {
|
|
605
|
+
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
606
|
+
if ("response" in resolved) return resolved.response;
|
|
607
|
+
const visibility = (await c.req.json().catch(() => void 0))?.visibility;
|
|
608
|
+
if (visibility !== "private" && visibility !== "org") return c.json({ error: "visibility must be 'private' or 'org'" }, 400);
|
|
609
|
+
const sessionId = c.req.param("sessionId");
|
|
610
|
+
const match = await resolveSession(options.sourceControls, sessionId);
|
|
611
|
+
const row = match?.session;
|
|
612
|
+
if (!match || !row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
|
|
613
|
+
if (!options.workItems) return c.json({ error: "Session visibility can't be changed yet: Factory storage is still starting up. Try again in a moment." }, 503);
|
|
614
|
+
if (row.branch.startsWith(SLACK_SESSION_BRANCH_PREFIX) || await isRunBound(row, options.workItems)) return c.json({ error: "Only user sessions can change visibility" }, 409);
|
|
615
|
+
if (visibility === "org" && !row.factoryProjectId) return c.json({ error: "This session isn't linked to a Factory, so it can't be shared." }, 409);
|
|
616
|
+
const resourceId = userSessionResourceFor(row, visibility);
|
|
617
|
+
const controller = options.controller;
|
|
618
|
+
const threadIds = controller ? await sessionThreadsToMove(controller, row, resourceId) : [];
|
|
619
|
+
if (threadIds.length > 0 && !options.moveThread) return c.json({ error: "Changing session visibility is not available on this server." }, 503);
|
|
620
|
+
if (controller?.listActiveThreadRuns().some((run) => threadIds.includes(run.threadId))) return c.json({ error: "Wait for the session to finish its run before changing visibility" }, 409);
|
|
621
|
+
const moveThreads = async (to) => {
|
|
622
|
+
for (const threadId of threadIds) await options.moveThread({
|
|
623
|
+
threadId,
|
|
624
|
+
resourceId: to
|
|
625
|
+
});
|
|
626
|
+
};
|
|
627
|
+
if (visibility === "private") await moveThreads(resourceId);
|
|
628
|
+
const updated = await match.sourceControl.sessions.setVisibility({
|
|
629
|
+
sessionId,
|
|
630
|
+
visibility,
|
|
631
|
+
expectedUserId: row.userId
|
|
632
|
+
});
|
|
633
|
+
if (!updated) {
|
|
634
|
+
if (visibility === "private") await moveThreads(userSessionResourceFor(row, "org"));
|
|
635
|
+
return c.json({ error: "Session not found" }, 404);
|
|
636
|
+
}
|
|
637
|
+
if (visibility === "org") await moveThreads(resourceId);
|
|
638
|
+
const live = await controller?.getSession(sessionId);
|
|
639
|
+
if (live && threadIds.length > 0) await controller.deleteSession({ sessionId });
|
|
640
|
+
else if (live) await controller.setResourceId(live, { resourceId });
|
|
641
|
+
const owners = await resolveOwnerProfiles([updated.userId]);
|
|
642
|
+
return c.json({ session: withOwnerProfile(updated, owners) });
|
|
643
|
+
}
|
|
644
|
+
}),
|
|
425
645
|
registerApiRoute("/web/user-sessions/:sessionId/title", {
|
|
426
646
|
method: "POST",
|
|
427
647
|
requiresAuth: false,
|
|
@@ -433,7 +653,7 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
433
653
|
const row = match?.session;
|
|
434
654
|
if (!match || !row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
|
|
435
655
|
if (!options.controller) return c.json({ error: "Sessions are not available on this server." }, 503);
|
|
436
|
-
const thread = (await options.controller
|
|
656
|
+
const thread = (await listFactorySessionThreads(options.controller, row, options.workItems)).sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];
|
|
437
657
|
if (!thread) return c.json({ error: "This session has no conversation to name yet." }, 409);
|
|
438
658
|
const stored = await options.memorySettings.get({
|
|
439
659
|
orgId: row.orgId,
|
|
@@ -448,7 +668,7 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
448
668
|
const title = await nameSession(sessionId, async () => {
|
|
449
669
|
const generated = await options.controller.generateThreadTitle({
|
|
450
670
|
threadId: thread.id,
|
|
451
|
-
|
|
671
|
+
sessionId,
|
|
452
672
|
requestContext,
|
|
453
673
|
...stored?.observerModelId ? { model: titleModel(stored.observerModelId) } : {}
|
|
454
674
|
});
|