@xfey/tutti 0.1.127 → 0.1.129

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 (85) hide show
  1. package/dist/approvals/decision-command.d.ts +2 -2
  2. package/dist/chat-assistant/diagnostics.d.ts +17 -3
  3. package/dist/chat-assistant/diagnostics.js +5 -2
  4. package/dist/chat-assistant/failure-messages.d.ts +4 -0
  5. package/dist/chat-assistant/failure-messages.js +57 -0
  6. package/dist/chat-assistant/failures.d.ts +27 -0
  7. package/dist/chat-assistant/failures.js +46 -0
  8. package/dist/chat-assistant/index.d.ts +18 -4
  9. package/dist/chat-assistant/index.js +254 -51
  10. package/dist/chat-assistant/language-context.d.ts +2 -0
  11. package/dist/chat-assistant/language-context.js +17 -14
  12. package/dist/chat-assistant/requests.d.ts +34 -0
  13. package/dist/chat-assistant/requests.js +64 -0
  14. package/dist/collaboration-ingestion/clarification.js +3 -1
  15. package/dist/collaboration-ingestion/main-chat.js +1 -0
  16. package/dist/collaboration-ingestion/types.d.ts +2 -0
  17. package/dist/collaboration-state/clarification-snapshot.d.ts +5 -5
  18. package/dist/collaboration-state/context-sync-attempts.d.ts +9 -0
  19. package/dist/collaboration-state/context-sync-attempts.js +13 -0
  20. package/dist/collaboration-state/task-compile-context.d.ts +1 -1
  21. package/dist/collaboration-state/task-compile-context.js +11 -1
  22. package/dist/collaboration-state/task-compile-requests.d.ts +6 -0
  23. package/dist/collaboration-state/task-compile-requests.js +16 -0
  24. package/dist/communication-language/notice-locale.d.ts +4 -0
  25. package/dist/communication-language/notice-locale.js +14 -0
  26. package/dist/control-plane/context-sync-completion.d.ts +7 -0
  27. package/dist/control-plane/context-sync-completion.js +27 -0
  28. package/dist/control-plane/context-sync.d.ts +1 -0
  29. package/dist/control-plane/context-sync.js +23 -0
  30. package/dist/control-plane/index.d.ts +13 -4
  31. package/dist/control-plane/index.js +30 -23
  32. package/dist/control-plane/task-compile-continuation.js +2 -0
  33. package/dist/control-plane/task-compile-request-status.d.ts +6 -0
  34. package/dist/control-plane/task-compile-request-status.js +70 -0
  35. package/dist/control-plane/task-compile-start.js +40 -2
  36. package/dist/control-plane/types.d.ts +2 -0
  37. package/dist/providers/failure-classification.d.ts +23 -0
  38. package/dist/providers/failure-classification.js +43 -0
  39. package/dist/providers/invocation-progress.d.ts +6 -0
  40. package/dist/providers/invocation-progress.js +24 -0
  41. package/dist/providers/openai/app-server/read-only-procedure.js +1 -0
  42. package/dist/providers/openai/chat-assistant.js +2 -1
  43. package/dist/reference-access/read-evidence.d.ts +2 -0
  44. package/dist/reference-access/read-evidence.js +5 -0
  45. package/dist/reference-access/service.d.ts +2 -0
  46. package/dist/reference-access/service.js +2 -0
  47. package/dist/runtime-failures.js +15 -1
  48. package/dist/server-shell/cli/external-reference-runtime.js +6 -3
  49. package/dist/server-shell/cli/host-server-runtime.js +8 -2
  50. package/dist/server-shell/cli/relay-registration.js +1 -0
  51. package/dist/server-shell/http/routes/project-api/messages-routes.js +22 -1
  52. package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +140 -5
  53. package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.js +29 -2
  54. package/dist/server-shell/http/routes/project-api/openapi-skills-routes.d.ts +2 -0
  55. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +6 -0
  56. package/dist/server-shell/http/routes/project-api/openapi.d.ts +148 -5
  57. package/dist/server-shell/http/routes/project-api/schemas.d.ts +6 -0
  58. package/dist/server-shell/http/routes/project-api/schemas.js +1 -0
  59. package/dist/server-shell/http/routes/project-api/types.d.ts +1 -0
  60. package/dist/server-shell/http/routes/project-api/workflow-routes.js +39 -3
  61. package/dist/server-shell/http/routes/project-api/workspace-projections.js +1 -0
  62. package/dist/server-shell/http/validation.js +8 -2
  63. package/dist/server-shell/local-console/managed-project-service.d.ts +1 -1
  64. package/dist/server-shell/managed-access/transport.d.ts +1 -1
  65. package/migrations/0024_chat_requests.sql +19 -0
  66. package/migrations/0025_task_compile_requests.sql +50 -0
  67. package/migrations/0026_context_sync_and_chat_locale.sql +12 -0
  68. package/migrations/README.md +3 -1
  69. package/node_modules/@tutti/relay-client/dist/host-control.d.ts +1 -0
  70. package/node_modules/@tutti/relay-client/dist/host-control.js +1 -0
  71. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -0
  72. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -0
  73. package/node_modules/@tutti/shared/dist/schemas/api/operation-status.d.ts +174 -0
  74. package/node_modules/@tutti/shared/dist/schemas/api/operation-status.js +75 -0
  75. package/node_modules/@tutti/shared/dist/schemas/api/primitives.d.ts +1 -0
  76. package/node_modules/@tutti/shared/dist/schemas/api/primitives.js +1 -0
  77. package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +1 -0
  78. package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.js +2 -1
  79. package/package.json +1 -1
  80. package/web/assets/{homepage-motion-scene-DyEmWwvt.js → homepage-motion-scene-BHhw4CfM.js} +1 -1
  81. package/web/assets/index-5COc1Yku.js +70 -0
  82. package/web/assets/index-BJvKuUiT.css +1 -0
  83. package/web/index.html +2 -2
  84. package/web/assets/index-By3idT4U.js +0 -70
  85. package/web/assets/index-DSBjOZmJ.css +0 -1
@@ -17,6 +17,8 @@ export type Phase5ControlPlaneOptions = {
17
17
  mainline_clean: boolean;
18
18
  };
19
19
  readActiveApproval?: () => ActiveApprovalProjection;
20
+ /** Read-only Chat owner signal; does not merge Chat into the workflow state machine. */
21
+ hasPendingChatRequests?: () => boolean;
20
22
  logger?: ControlPlaneLogger;
21
23
  projectContext?: {
22
24
  workspaceRoot: string;
@@ -0,0 +1,23 @@
1
+ declare const aliases: {
2
+ readonly provider_not_configured: "provider_not_configured";
3
+ readonly provider_auth_invalid: "provider_auth_invalid";
4
+ readonly provider_quota_or_billing_required: "provider_quota_or_billing_required";
5
+ readonly provider_rate_limited: "provider_rate_limited";
6
+ readonly provider_model_unavailable: "provider_model_unavailable";
7
+ readonly provider_network_error: "provider_network_error";
8
+ readonly auth_failed: "provider_auth_invalid";
9
+ readonly host_delegation_revoked: "provider_auth_invalid";
10
+ readonly authority_invalid: "provider_auth_invalid";
11
+ readonly gateway_rate_limited: "provider_rate_limited";
12
+ readonly control_queue_full: "provider_rate_limited";
13
+ readonly turn_timeout: "provider_timeout";
14
+ readonly output_parse_failed: "provider_output_invalid";
15
+ readonly output_validation_failed: "provider_output_invalid";
16
+ readonly process_lifecycle_failed: "provider_lifecycle_failed";
17
+ readonly process_tree_not_terminated: "provider_lifecycle_failed";
18
+ };
19
+ export type ProviderFailureCode = (typeof aliases)[keyof typeof aliases];
20
+ /** Facts only, never a retry policy. Do not parse provider prose or raw stderr. */
21
+ export declare function providerFailureCode(error: unknown): ProviderFailureCode | undefined;
22
+ export {};
23
+ //# sourceMappingURL=failure-classification.d.ts.map
@@ -0,0 +1,43 @@
1
+ const aliases = {
2
+ provider_not_configured: "provider_not_configured",
3
+ provider_auth_invalid: "provider_auth_invalid",
4
+ provider_quota_or_billing_required: "provider_quota_or_billing_required",
5
+ provider_rate_limited: "provider_rate_limited",
6
+ provider_model_unavailable: "provider_model_unavailable",
7
+ provider_network_error: "provider_network_error",
8
+ auth_failed: "provider_auth_invalid",
9
+ host_delegation_revoked: "provider_auth_invalid",
10
+ authority_invalid: "provider_auth_invalid",
11
+ gateway_rate_limited: "provider_rate_limited",
12
+ control_queue_full: "provider_rate_limited",
13
+ turn_timeout: "provider_timeout",
14
+ output_parse_failed: "provider_output_invalid",
15
+ output_validation_failed: "provider_output_invalid",
16
+ process_lifecycle_failed: "provider_lifecycle_failed",
17
+ process_tree_not_terminated: "provider_lifecycle_failed",
18
+ };
19
+ /** Facts only, never a retry policy. Do not parse provider prose or raw stderr. */
20
+ export function providerFailureCode(error) {
21
+ if (typeof error !== "object" || error === null)
22
+ return undefined;
23
+ const value = error;
24
+ const code = typeof value.code === "string" ? value.code : value.reason;
25
+ if (typeof code === "string" && Object.hasOwn(aliases, code))
26
+ return aliases[code];
27
+ if (code !== "turn_failed" || typeof value.details !== "object" || value.details === null)
28
+ return undefined;
29
+ const details = value.details;
30
+ // Quota can also carry HTTP 429; the specific bounded code takes precedence.
31
+ if (details.turn_error_code === "insufficient_quota")
32
+ return "provider_quota_or_billing_required";
33
+ if (details.turn_error_code === "invalid_api_key")
34
+ return "provider_auth_invalid";
35
+ if (details.turn_error_code === "model_not_found")
36
+ return "provider_model_unavailable";
37
+ if (details.turn_error_code === "rate_limit_exceeded" || details.turn_error_http_status === 429)
38
+ return "provider_rate_limited";
39
+ if (details.turn_error_http_status === 401)
40
+ return "provider_auth_invalid";
41
+ return undefined;
42
+ }
43
+ //# sourceMappingURL=failure-classification.js.map
@@ -3,8 +3,14 @@ export type ProviderInvocationProgress = {
3
3
  invocation_ref?: string;
4
4
  skill_count?: number;
5
5
  completed_tool_count?: number;
6
+ turn_timeout_ms?: number;
7
+ notification_count?: number;
8
+ server_request_count?: number;
9
+ last_activity_age_ms?: number;
6
10
  reason_code?: "provider_unavailable" | "app_server_protocol_error" | "auth_failed" | "thread_start_failed" | "turn_failed" | "turn_timeout" | "unexpected_server_request" | "skill_selection_failed" | "output_parse_failed" | "output_validation_failed" | "file_read_not_observed" | "write_detected" | "secret_leak_detected" | "process_lifecycle_failed" | "admission_unavailable";
7
11
  };
8
12
  export type ProviderInvocationProgressObserver = (event: ProviderInvocationProgress) => void;
13
+ /** Copy only finite counters. Do not forward raw error details/methods/prose. */
14
+ export declare function providerInvocationFailureCounters(error: unknown, now?: number): Partial<ProviderInvocationProgress>;
9
15
  export declare function reportProviderInvocationProgress(observer: ProviderInvocationProgressObserver | undefined, event: ProviderInvocationProgress): void;
10
16
  //# sourceMappingURL=invocation-progress.d.ts.map
@@ -1,3 +1,27 @@
1
+ /** Copy only finite counters. Do not forward raw error details/methods/prose. */
2
+ export function providerInvocationFailureCounters(error, now = Date.now()) {
3
+ if (typeof error !== "object" || error === null || !("details" in error))
4
+ return {};
5
+ const details = error.details;
6
+ if (typeof details !== "object" || details === null)
7
+ return {};
8
+ const source = details;
9
+ const counters = {};
10
+ for (const key of ["turn_timeout_ms", "notification_count", "completed_tool_count"]) {
11
+ const value = source[key];
12
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
13
+ counters[key] = value;
14
+ }
15
+ if (Array.isArray(source.server_request_methods))
16
+ counters.server_request_count = source.server_request_methods.length;
17
+ if (typeof source.last_activity_at === "string" &&
18
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(source.last_activity_at)) {
19
+ const age = now - Date.parse(source.last_activity_at);
20
+ if (Number.isSafeInteger(age) && age >= 0)
21
+ counters.last_activity_age_ms = age;
22
+ }
23
+ return counters;
24
+ }
1
25
  export function reportProviderInvocationProgress(observer, event) {
2
26
  try {
3
27
  observer?.(event);
@@ -55,6 +55,7 @@ function readOnlyTimeoutDetails(input) {
55
55
  const details = {
56
56
  turn_timeout_ms: input.turnTimeoutMs,
57
57
  notification_count: input.client.notifications.length,
58
+ completed_tool_count: structuredOutputDetails(input.client, "").completed_tool_count ?? 0,
58
59
  server_request_methods: input.client.serverRequests.map(extractServerRequestMethod),
59
60
  notification_methods: input.client.notifications
60
61
  .map((notification) => notification.method)
@@ -3,7 +3,7 @@ import { readOpenAiApiKeyCredential } from "./credential-store.js";
3
3
  import { resolveOpenAiProviderConfig } from "./provider-config.js";
4
4
  import { openAiCredentialAccess, } from "./execution-access.js";
5
5
  import { CodexAppServerReadOnlyProcedureError, runCodexAppServerReadOnlyProcedure, } from "./app-server/read-only-procedure.js";
6
- import { reportProviderInvocationProgress } from "../invocation-progress.js";
6
+ import { reportProviderInvocationProgress, providerInvocationFailureCounters, } from "../invocation-progress.js";
7
7
  import { getProjectUserSkillsRoot } from "../../skills/index.js";
8
8
  export function createOpenAiReadOnlyChatAssistantModel(options) {
9
9
  return {
@@ -42,6 +42,7 @@ export function createOpenAiReadOnlyChatAssistantModel(options) {
42
42
  : { onLifecycleIncident: options.onLifecycleIncident }),
43
43
  }).catch((error) => {
44
44
  reportProviderInvocationProgress(input.onProgress, {
45
+ ...providerInvocationFailureCounters(error),
45
46
  stage: "provider_failed",
46
47
  reason_code: error instanceof CodexAppServerReadOnlyProcedureError
47
48
  ? error.code
@@ -1,6 +1,8 @@
1
1
  import type { SqliteDatabase } from "../store/index.js";
2
2
  import type { ReferenceCopy } from "./cache.js";
3
3
  import type { ReferenceInvocation } from "./service.js";
4
+ import type { ReferenceAuthorization } from "@tutti/shared/schemas/api";
5
+ export declare function recordExternalReferenceAccessRequirement(db: SqliteDatabase, invocation: ReferenceInvocation, requestRef: string, authorization: ReferenceAuthorization, now?: () => Date): void;
4
6
  /** Prior answer context only: a source reference is not proof of freshness in a later turn. */
5
7
  export declare function readExternalReferenceReadSources(db: SqliteDatabase, invocationRef: string): string[];
6
8
  /** Durable observation, separate from evictable cache metadata; no content or locator. */
@@ -1,3 +1,8 @@
1
+ export function recordExternalReferenceAccessRequirement(db, invocation, requestRef, authorization, now = () => new Date()) {
2
+ db.prepare(`INSERT OR IGNORE INTO external_reference_access_requirements
3
+ (invocation_ref, request_ref, activity_ref, authorization_ref, profile, observed_at)
4
+ VALUES (?, ?, ?, ?, ?, ?)`).run(invocation.reference_invocation_ref, requestRef, invocation.activity_ref ?? null, authorization.authorization_ref, authorization.profile, now().toISOString());
5
+ }
1
6
  /** Prior answer context only: a source reference is not proof of freshness in a later turn. */
2
7
  export function readExternalReferenceReadSources(db, invocationRef) {
3
8
  return db
@@ -8,6 +8,8 @@ export type ReferenceInvocation = {
8
8
  };
9
9
  export declare class ReferenceAuthorizationRequiredError extends Error {
10
10
  readonly result: ReferenceAuthorizationRequired;
11
+ readonly code = "reference_authorization_required";
12
+ readonly continuation = "explicit_request";
11
13
  constructor(result: ReferenceAuthorizationRequired);
12
14
  }
13
15
  export declare class ExternalReferenceAccess {
@@ -1,6 +1,8 @@
1
1
  import { ReferenceCacheError } from "./cache.js";
2
2
  export class ReferenceAuthorizationRequiredError extends Error {
3
3
  result;
4
+ code = "reference_authorization_required";
5
+ continuation = "explicit_request";
4
6
  constructor(result) {
5
7
  super("reference_authorization_required");
6
8
  this.result = result;
@@ -1,3 +1,4 @@
1
+ import { providerFailureCode } from "./providers/failure-classification.js";
1
2
  const STABLE_FAILURE_CODE = /^[a-z][a-z0-9_]{0,63}$/u;
2
3
  export function stableRuntimeFailureCode(error, fallback) {
3
4
  if (typeof error === "object" &&
@@ -17,6 +18,19 @@ export function safeRuntimeFailureSummary(subject, error, fallbackCode) {
17
18
  if (code === "admission_unavailable" || code === "admission_closed") {
18
19
  return `${subject} stopped because provider execution is unavailable while the Host is closing. Retry after the Host is ready. (${code})`;
19
20
  }
20
- return `${subject} failed because the runtime returned an internal error. Retry the action. (${code})`;
21
+ if (code === "reference_authorization_required") {
22
+ return `${subject} needs document access. Authorize using the group card, then review the task or request before continuing. (${code})`;
23
+ }
24
+ const providerCode = providerFailureCode(error);
25
+ if (providerCode === "provider_auth_invalid" ||
26
+ providerCode === "provider_quota_or_billing_required" ||
27
+ providerCode === "provider_model_unavailable" ||
28
+ providerCode === "provider_not_configured") {
29
+ return `${subject} could not use model access. Ask the project owner to check the provider or account, then review available recovery actions. (${providerCode})`;
30
+ }
31
+ if (providerCode === "provider_rate_limited") {
32
+ return `${subject} stopped because the model service is busy. Wait, then review available recovery actions. (${providerCode})`;
33
+ }
34
+ return `${subject} could not complete. Review its status and available recovery actions before continuing. (${code})`;
21
35
  }
22
36
  //# sourceMappingURL=runtime-failures.js.map
@@ -4,7 +4,7 @@ import { requestExternalReferences } from "@tutti/relay-client";
4
4
  import { isExternalReferenceList, isExternalReferenceReadResult, isExternalReferenceDescriptor, isReferenceAuthorizationRequired, } from "@tutti/shared/schemas/internal";
5
5
  import { ExternalReferenceCache } from "../../reference-access/cache.js";
6
6
  import { ExternalReferenceAccess, ReferenceAuthorizationRequiredError, } from "../../reference-access/service.js";
7
- import { recordExternalReferenceRead } from "../../reference-access/read-evidence.js";
7
+ import { recordExternalReferenceRead, recordExternalReferenceAccessRequirement, } from "../../reference-access/read-evidence.js";
8
8
  import { downloadStagedUploadWithResolver, cleanupDownloadedStagedUpload, } from "../http/routes/project-api/staged-uploads.js";
9
9
  import { readHostRegistrationSecret } from "./machine-local.js";
10
10
  export function createExternalReferenceRuntime(options) {
@@ -14,6 +14,7 @@ export function createExternalReferenceRuntime(options) {
14
14
  if (!relay)
15
15
  throw new Error("reference_host_offline");
16
16
  const secret = readHostRegistrationSecret(preparation.tutti_home, preparation.project_id);
17
+ const requestRef = `eref_${randomUUID().replaceAll("-", "")}`;
17
18
  const result = await requestExternalReferences({
18
19
  relayUrl: preparation.relay_url,
19
20
  body: {
@@ -22,15 +23,17 @@ export function createExternalReferenceRuntime(options) {
22
23
  host_auth: { kind: "host_registration_secret_v1", secret: secret.secret },
23
24
  relay_project_ref: relay.relay_project_ref,
24
25
  host_connection_ref: relay.host_connection_ref,
25
- request_ref: `eref_${randomUUID().replaceAll("-", "")}`,
26
+ request_ref: requestRef,
26
27
  invocation_ref: invocation.reference_invocation_ref,
27
28
  action,
28
29
  ...(sourceRef === undefined ? {} : { source_ref: sourceRef }),
29
30
  ...(documentUrl === undefined ? {} : { document_url: documentUrl }),
30
31
  },
31
32
  });
32
- if (isReferenceAuthorizationRequired(result))
33
+ if (isReferenceAuthorizationRequired(result)) {
34
+ recordExternalReferenceAccessRequirement(options.store.db, invocation, requestRef, result.authorization);
33
35
  throw new ReferenceAuthorizationRequiredError(result);
36
+ }
34
37
  return result;
35
38
  }
36
39
  return new ExternalReferenceAccess({
@@ -1,4 +1,5 @@
1
1
  import { basename, join } from "node:path";
2
+ import { hasPendingChatRequests } from "../../chat-assistant/requests.js";
2
3
  import { MAX_PROVIDER_MODEL_NAME_LENGTH, } from "@tutti/shared/schemas/api";
3
4
  import { serializeRuntimeLogLine } from "@tutti/shared/utils";
4
5
  import { completeRelayUpload, deliverRelayPlatformOutbound, RelayHostControlClientError, resolveRelayUpload, } from "@tutti/relay-client";
@@ -397,6 +398,7 @@ export async function startForegroundHostServer(options) {
397
398
  events: workspaceEvents,
398
399
  now,
399
400
  logger: controlPlaneLogger,
401
+ hasPendingChatRequests: () => hasPendingChatRequests(store.db),
400
402
  projectContext,
401
403
  runLifecycle: {
402
404
  started: () => artifactPreviewManager.beginWorkspaceUpdate(),
@@ -464,12 +466,15 @@ export async function startForegroundHostServer(options) {
464
466
  model: createManagedChatModel(managedRuntime, runtimeOptions),
465
467
  };
466
468
  if (resolution.kind !== "ready") {
467
- throw new Error("Provider is not configured.");
469
+ throw Object.assign(new Error("Provider is not configured."), {
470
+ code: "provider_not_configured",
471
+ });
468
472
  }
469
473
  return await resolution.model.answer(input);
470
474
  },
471
475
  },
472
- waitForInspectionAvailability: () => controlPlane.waitForRepoInspectionIdle(),
476
+ waitForInspectionAvailability: (onBlocked) => controlPlane.waitForRepoInspectionIdle(onBlocked),
477
+ onRequestsChanged: () => controlPlane.notifyChatRequestsChanged(),
473
478
  onScratchpadSourceChanged: (message) => controlPlane.notifyScratchpadSourceChanged(message),
474
479
  ...(platformOutboundCoordinator === undefined
475
480
  ? {}
@@ -704,6 +709,7 @@ export async function startForegroundHostServer(options) {
704
709
  workspaceRoot: options.preparation.workspace_root,
705
710
  recoverInProgressCommands: true,
706
711
  });
712
+ chatAssistant.start();
707
713
  };
708
714
  // Managed creation / reauthorization activates during Relay registration. Do
709
715
  // not recover a stored task against a not-yet-activated native delegation.
@@ -66,6 +66,7 @@ export async function registerHostWithRelay(options) {
66
66
  integration_development_bot_v1: true,
67
67
  integration_clarification_v1: true,
68
68
  feishu_supporting_reads_v1: true,
69
+ request_status_v1: true,
69
70
  integration_external_references_v1: true,
70
71
  integration_attachment_ingestion_v1: true,
71
72
  integration_managed_reference_ingestion_v1: true,
@@ -1,11 +1,32 @@
1
- import { GetMessagesRequestSchema, MessageWindowSchema, SendMainChatMessageBodySchema, SendMainChatMessageResponseSchema, } from "@tutti/shared/schemas/api";
1
+ import { Type } from "@sinclair/typebox";
2
+ import { MessageIdSchema } from "@tutti/shared/schemas/domain";
3
+ import { GetMessagesRequestSchema, ChatRequestStatusSchema, MessageWindowSchema, SendMainChatMessageBodySchema, SendMainChatMessageResponseSchema, } from "@tutti/shared/schemas/api";
2
4
  import { createArtifactFeedbackMessage } from "../../../../artifact-feedback/index.js";
3
5
  import { ingestMainChatMessage } from "../../../../collaboration-ingestion/index.js";
4
6
  import { readMainChatMessageWindow } from "../../../../collaboration-state/index.js";
5
7
  import { HOST_PROJECT_API_BASE_PATH } from "./constants.js";
6
8
  import { requireValidMessageWindowRequest, requireValidSendMainChatPayload, } from "./payload-validation.js";
7
9
  import { requireHostProjectSession, requireProjectStore, requireWorkspaceRoot, } from "./session-requirements.js";
10
+ import { HostProjectNotFoundError, HostProjectBadRequestError } from "./errors.js";
11
+ import { chatRequestStatus, readChatRequest } from "../../../../chat-assistant/requests.js";
8
12
  export function registerMessagesRoutes(app, { options, workspaceEvents, artifactPreviewManager, }) {
13
+ app.get(`${HOST_PROJECT_API_BASE_PATH}/chat-requests/:messageId`, {
14
+ preValidation: (request, _reply, done) => done(Object.keys(request.query).length === 0
15
+ ? undefined
16
+ : new HostProjectBadRequestError("Request status does not accept query parameters")),
17
+ schema: {
18
+ params: Type.Object({ messageId: MessageIdSchema }, { additionalProperties: false }),
19
+ querystring: Type.Object({}, { additionalProperties: false }),
20
+ response: { 200: ChatRequestStatusSchema },
21
+ },
22
+ }, (request, reply) => {
23
+ requireHostProjectSession(request, options);
24
+ reply.header("cache-control", "no-store");
25
+ const record = readChatRequest(requireProjectStore(options).db, request.params.messageId);
26
+ if (record === null)
27
+ throw new HostProjectNotFoundError();
28
+ return chatRequestStatus(record);
29
+ });
9
30
  app.get(`${HOST_PROJECT_API_BASE_PATH}/messages`, {
10
31
  schema: {
11
32
  querystring: GetMessagesRequestSchema,
@@ -1,4 +1,139 @@
1
1
  export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
2
+ method: "get";
3
+ path: string;
4
+ summary: string;
5
+ tags: string[];
6
+ querystring: import("@sinclair/typebox").TObject<{
7
+ workflow_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
8
+ command_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
+ }>;
10
+ responses: {
11
+ 200: {
12
+ description: string;
13
+ schema: import("@sinclair/typebox").TObject<{
14
+ request: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
15
+ status: import("@sinclair/typebox").TLiteral<"running">;
16
+ phase: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"preparing">, import("@sinclair/typebox").TLiteral<"scratchpad_refresh">, import("@sinclair/typebox").TLiteral<"reference_summary_refresh">, import("@sinclair/typebox").TLiteral<"project_context_bootstrap">, import("@sinclair/typebox").TLiteral<"task_compile">]>;
17
+ operation: import("@sinclair/typebox").TObject<{
18
+ kind: import("@sinclair/typebox").TLiteral<"worklist_submit">;
19
+ ref: import("@sinclair/typebox").TString;
20
+ }>;
21
+ created_at: import("@sinclair/typebox").TString;
22
+ activity_ref: import("@sinclair/typebox").TString;
23
+ }>, import("@sinclair/typebox").TObject<{
24
+ status: import("@sinclair/typebox").TLiteral<"waiting_input">;
25
+ phase: import("@sinclair/typebox").TLiteral<"clarification">;
26
+ round_id: import("@sinclair/typebox").TString;
27
+ operation: import("@sinclair/typebox").TObject<{
28
+ kind: import("@sinclair/typebox").TLiteral<"worklist_submit">;
29
+ ref: import("@sinclair/typebox").TString;
30
+ }>;
31
+ created_at: import("@sinclair/typebox").TString;
32
+ activity_ref: import("@sinclair/typebox").TString;
33
+ }>, import("@sinclair/typebox").TObject<{
34
+ status: import("@sinclair/typebox").TLiteral<"succeeded">;
35
+ phase: import("@sinclair/typebox").TLiteral<"settled">;
36
+ operation: import("@sinclair/typebox").TObject<{
37
+ kind: import("@sinclair/typebox").TLiteral<"worklist_submit">;
38
+ ref: import("@sinclair/typebox").TString;
39
+ }>;
40
+ created_at: import("@sinclair/typebox").TString;
41
+ activity_ref: import("@sinclair/typebox").TString;
42
+ }>, import("@sinclair/typebox").TObject<{
43
+ status: import("@sinclair/typebox").TLiteral<"failed">;
44
+ phase: import("@sinclair/typebox").TLiteral<"settled">;
45
+ failure: import("@sinclair/typebox").TObject<{
46
+ code: import("@sinclair/typebox").TString;
47
+ category: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"interrupted" | "capacity" | "access" | "configuration" | "dependency" | "internal">[]>;
48
+ recovery: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"resend_request" | "check_provider" | "restart_host" | "contact_support" | "none">[]>;
49
+ diagnostic_id: import("@sinclair/typebox").TString;
50
+ }>;
51
+ operation: import("@sinclair/typebox").TObject<{
52
+ kind: import("@sinclair/typebox").TLiteral<"worklist_submit">;
53
+ ref: import("@sinclair/typebox").TString;
54
+ }>;
55
+ created_at: import("@sinclair/typebox").TString;
56
+ activity_ref: import("@sinclair/typebox").TString;
57
+ }>, import("@sinclair/typebox").TObject<{
58
+ status: import("@sinclair/typebox").TLiteral<"unknown">;
59
+ phase: import("@sinclair/typebox").TLiteral<"unconfirmed">;
60
+ operation: import("@sinclair/typebox").TObject<{
61
+ kind: import("@sinclair/typebox").TLiteral<"worklist_submit">;
62
+ ref: import("@sinclair/typebox").TString;
63
+ }>;
64
+ created_at: import("@sinclair/typebox").TString;
65
+ activity_ref: import("@sinclair/typebox").TString;
66
+ }>]>, import("@sinclair/typebox").TNull]>;
67
+ }>;
68
+ contentType?: never;
69
+ };
70
+ };
71
+ parameters?: never;
72
+ requestBody?: never;
73
+ } | {
74
+ method: "get";
75
+ path: string;
76
+ summary: string;
77
+ tags: string[];
78
+ parameters: import("@tutti/shared/schemas/api").BrowserFacingOpenApiParameter[];
79
+ responses: {
80
+ 200: {
81
+ description: string;
82
+ schema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
83
+ status: import("@sinclair/typebox").TLiteral<"queued">;
84
+ phase: import("@sinclair/typebox").TLiteral<"queue">;
85
+ operation: import("@sinclair/typebox").TObject<{
86
+ kind: import("@sinclair/typebox").TLiteral<"chat_answer">;
87
+ ref: import("@sinclair/typebox").TString;
88
+ }>;
89
+ revision: import("@sinclair/typebox").TInteger;
90
+ created_at: import("@sinclair/typebox").TString;
91
+ updated_at: import("@sinclair/typebox").TString;
92
+ }>, import("@sinclair/typebox").TObject<{
93
+ status: import("@sinclair/typebox").TLiteral<"running">;
94
+ phase: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"workspace_wait">, import("@sinclair/typebox").TLiteral<"answer">]>;
95
+ operation: import("@sinclair/typebox").TObject<{
96
+ kind: import("@sinclair/typebox").TLiteral<"chat_answer">;
97
+ ref: import("@sinclair/typebox").TString;
98
+ }>;
99
+ revision: import("@sinclair/typebox").TInteger;
100
+ created_at: import("@sinclair/typebox").TString;
101
+ updated_at: import("@sinclair/typebox").TString;
102
+ }>, import("@sinclair/typebox").TObject<{
103
+ status: import("@sinclair/typebox").TLiteral<"succeeded">;
104
+ phase: import("@sinclair/typebox").TLiteral<"settled">;
105
+ response_message_id: import("@sinclair/typebox").TString;
106
+ operation: import("@sinclair/typebox").TObject<{
107
+ kind: import("@sinclair/typebox").TLiteral<"chat_answer">;
108
+ ref: import("@sinclair/typebox").TString;
109
+ }>;
110
+ revision: import("@sinclair/typebox").TInteger;
111
+ created_at: import("@sinclair/typebox").TString;
112
+ updated_at: import("@sinclair/typebox").TString;
113
+ }>, import("@sinclair/typebox").TObject<{
114
+ status: import("@sinclair/typebox").TLiteral<"failed">;
115
+ phase: import("@sinclair/typebox").TLiteral<"settled">;
116
+ failure: import("@sinclair/typebox").TObject<{
117
+ code: import("@sinclair/typebox").TString;
118
+ category: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"interrupted" | "capacity" | "access" | "configuration" | "dependency" | "internal">[]>;
119
+ recovery: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"resend_request" | "check_provider" | "restart_host" | "contact_support" | "none">[]>;
120
+ diagnostic_id: import("@sinclair/typebox").TString;
121
+ }>;
122
+ response_message_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
123
+ operation: import("@sinclair/typebox").TObject<{
124
+ kind: import("@sinclair/typebox").TLiteral<"chat_answer">;
125
+ ref: import("@sinclair/typebox").TString;
126
+ }>;
127
+ revision: import("@sinclair/typebox").TInteger;
128
+ created_at: import("@sinclair/typebox").TString;
129
+ updated_at: import("@sinclair/typebox").TString;
130
+ }>]>;
131
+ contentType?: never;
132
+ };
133
+ };
134
+ querystring?: never;
135
+ requestBody?: never;
136
+ } | {
2
137
  method: "get";
3
138
  path: string;
4
139
  summary: string;
@@ -17,8 +152,8 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
17
152
  contentType?: never;
18
153
  };
19
154
  };
20
- requestBody?: never;
21
155
  parameters?: never;
156
+ requestBody?: never;
22
157
  } | {
23
158
  method: "post";
24
159
  path: string;
@@ -77,8 +212,8 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
77
212
  };
78
213
  };
79
214
  };
80
- requestBody?: never;
81
215
  parameters?: never;
216
+ requestBody?: never;
82
217
  } | {
83
218
  method: "get";
84
219
  path: string;
@@ -123,8 +258,8 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
123
258
  };
124
259
  };
125
260
  querystring?: never;
126
- requestBody?: never;
127
261
  parameters?: never;
262
+ requestBody?: never;
128
263
  } | {
129
264
  method: "get";
130
265
  path: string;
@@ -165,8 +300,8 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
165
300
  };
166
301
  };
167
302
  querystring?: never;
168
- requestBody?: never;
169
303
  parameters?: never;
304
+ requestBody?: never;
170
305
  } | {
171
306
  method: "post";
172
307
  path: string;
@@ -294,8 +429,8 @@ export declare const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES: ({
294
429
  };
295
430
  };
296
431
  querystring?: never;
297
- requestBody?: never;
298
432
  parameters?: never;
433
+ requestBody?: never;
299
434
  } | {
300
435
  method: "get";
301
436
  path: string;
@@ -1,8 +1,35 @@
1
- import { ActiveClarificationProjectionSchema, GetClarificationRoundMessagesRequestSchema, GetClarificationRoundResponseSchema, GetClarificationThreadResponseSchema, GetMessagesRequestSchema, MessageWindowSchema, RunSchedulerNowBodySchema, RunSchedulerNowResponseSchema, ScratchpadProjectionSchema, SendClarificationRoundMessageBodySchema, SendClarificationRoundMessageResponseSchema, SendMainChatMessageResponseSchema, SubmitClarificationRoundBodySchema, SubmitClarificationRoundResponseSchema, SubmitWorklistBodySchema, SubmitWorklistResponseSchema, WorklistProjectionSchema, } from "@tutti/shared/schemas/api";
1
+ import { ActiveClarificationProjectionSchema, ChatRequestStatusSchema, CurrentWorklistSubmissionSchema, WorklistSubmissionQuerySchema, GetClarificationRoundMessagesRequestSchema, GetClarificationRoundResponseSchema, GetClarificationThreadResponseSchema, GetMessagesRequestSchema, MessageWindowSchema, RunSchedulerNowBodySchema, RunSchedulerNowResponseSchema, ScratchpadProjectionSchema, SendClarificationRoundMessageBodySchema, SendClarificationRoundMessageResponseSchema, SendMainChatMessageResponseSchema, SubmitClarificationRoundBodySchema, SubmitClarificationRoundResponseSchema, SubmitWorklistBodySchema, SubmitWorklistResponseSchema, WorklistProjectionSchema, } from "@tutti/shared/schemas/api";
2
+ import { MessageIdSchema } from "@tutti/shared/schemas/domain";
2
3
  import { HOST_PROJECT_API_BASE_PATH } from "./constants.js";
3
4
  import { EventStreamResponseSchema, GetEventsRequestSchema, SendMainChatMessageBodySchema, } from "./schemas.js";
4
- import { ClarificationRoundIdPathParameter, ClarificationThreadIdPathParameter, } from "./openapi-path-parameters.js";
5
+ import { ClarificationRoundIdPathParameter, pathParameter, ClarificationThreadIdPathParameter, } from "./openapi-path-parameters.js";
5
6
  export const HOST_PROJECT_COLLABORATION_OPENAPI_ROUTES = [
7
+ {
8
+ method: "get",
9
+ path: `${HOST_PROJECT_API_BASE_PATH}/worklist/submission`,
10
+ summary: "Read the latest or identified Submit operation; acceptance is not completion.",
11
+ tags: ["worklist"],
12
+ querystring: WorklistSubmissionQuerySchema,
13
+ responses: {
14
+ 200: {
15
+ description: "Submission evidence or null when not recorded.",
16
+ schema: CurrentWorklistSubmissionSchema,
17
+ },
18
+ },
19
+ },
20
+ {
21
+ method: "get",
22
+ path: `${HOST_PROJECT_API_BASE_PATH}/chat-requests/{message_id}`,
23
+ summary: "Read a durable answer request by its trigger message id.",
24
+ tags: ["messages"],
25
+ parameters: [pathParameter("message_id", MessageIdSchema, "Original question message id.")],
26
+ responses: {
27
+ 200: {
28
+ description: "Host processing status, not platform delivery status.",
29
+ schema: ChatRequestStatusSchema,
30
+ },
31
+ },
32
+ },
6
33
  {
7
34
  method: "get",
8
35
  path: `${HOST_PROJECT_API_BASE_PATH}/messages`,
@@ -25,6 +25,7 @@ export declare const HOST_PROJECT_SKILLS_OPENAPI_ROUTES: ({
25
25
  message: import("@sinclair/typebox").TString;
26
26
  retryable: import("@sinclair/typebox").TBoolean;
27
27
  details: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
28
+ request_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
28
29
  }>;
29
30
  }>;
30
31
  };
@@ -60,6 +61,7 @@ export declare const HOST_PROJECT_SKILLS_OPENAPI_ROUTES: ({
60
61
  message: import("@sinclair/typebox").TString;
61
62
  retryable: import("@sinclair/typebox").TBoolean;
62
63
  details: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
64
+ request_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
63
65
  }>;
64
66
  }>;
65
67
  };
@@ -575,6 +575,9 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
575
575
  readonly artifact_feedback: {
576
576
  readonly type: "boolean";
577
577
  };
578
+ readonly request_status_v1: {
579
+ readonly type: "boolean";
580
+ };
578
581
  };
579
582
  };
580
583
  };
@@ -769,6 +772,9 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
769
772
  readonly artifact_feedback: {
770
773
  readonly type: "boolean";
771
774
  };
775
+ readonly request_status_v1: {
776
+ readonly type: "boolean";
777
+ };
772
778
  };
773
779
  };
774
780
  };