managed-deepagents 0.10.0-dev.9 → 0.10.1-dev.1
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 +864 -143
- package/dist/browser.d.ts +37 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +31 -0
- package/dist/browser.js.map +1 -0
- package/dist/channels/actor.d.ts +57 -0
- package/dist/channels/actor.d.ts.map +1 -0
- package/dist/channels/actor.js +24 -0
- package/dist/channels/actor.js.map +1 -0
- package/dist/channels/assistant-text.d.ts +29 -0
- package/dist/channels/assistant-text.d.ts.map +1 -1
- package/dist/channels/assistant-text.js +81 -4
- package/dist/channels/assistant-text.js.map +1 -1
- package/dist/channels/binding.d.ts +20 -1
- package/dist/channels/binding.d.ts.map +1 -1
- package/dist/channels/binding.js +44 -11
- package/dist/channels/binding.js.map +1 -1
- package/dist/channels/delivery.d.ts +51 -0
- package/dist/channels/delivery.d.ts.map +1 -0
- package/dist/channels/delivery.js +424 -0
- package/dist/channels/delivery.js.map +1 -0
- package/dist/channels/github/app-setup.d.ts +32 -0
- package/dist/channels/github/app-setup.d.ts.map +1 -0
- package/dist/channels/github/app-setup.js +146 -0
- package/dist/channels/github/app-setup.js.map +1 -0
- package/dist/channels/github/index.d.ts +5 -1
- package/dist/channels/github/index.d.ts.map +1 -1
- package/dist/channels/github/index.js +38 -46
- package/dist/channels/github/index.js.map +1 -1
- package/dist/channels/github/mentions.d.ts +12 -0
- package/dist/channels/github/mentions.d.ts.map +1 -0
- package/dist/channels/github/mentions.js +185 -0
- package/dist/channels/github/mentions.js.map +1 -0
- package/dist/channels/github/schema.d.ts +271 -0
- package/dist/channels/github/schema.d.ts.map +1 -1
- package/dist/channels/github/schema.js +33 -0
- package/dist/channels/github/schema.js.map +1 -1
- package/dist/channels/github/types.d.ts +50 -26
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/http/endpoint.d.ts +137 -0
- package/dist/channels/http/endpoint.d.ts.map +1 -0
- package/dist/channels/http/endpoint.js +286 -0
- package/dist/channels/http/endpoint.js.map +1 -0
- package/dist/channels/http/http.d.ts.map +1 -1
- package/dist/channels/http/http.js +209 -89
- package/dist/channels/http/http.js.map +1 -1
- package/dist/channels/http/index.d.ts +7 -1
- package/dist/channels/http/index.d.ts.map +1 -1
- package/dist/channels/http/index.js +32 -23
- package/dist/channels/http/index.js.map +1 -1
- package/dist/channels/http/ingress.d.ts +30 -24
- package/dist/channels/http/ingress.d.ts.map +1 -1
- package/dist/channels/http/ingress.js +61 -57
- package/dist/channels/http/ingress.js.map +1 -1
- package/dist/channels/http/provider.d.ts +38 -15
- package/dist/channels/http/provider.d.ts.map +1 -1
- package/dist/channels/http/provider.js +54 -24
- package/dist/channels/http/provider.js.map +1 -1
- package/dist/channels/http/studio.d.ts +8 -1
- package/dist/channels/http/studio.d.ts.map +1 -1
- package/dist/channels/http/studio.js +13 -0
- package/dist/channels/http/studio.js.map +1 -1
- package/dist/channels/http/types.d.ts +95 -69
- package/dist/channels/http/types.d.ts.map +1 -1
- package/dist/channels/linear/app-setup.d.ts +29 -0
- package/dist/channels/linear/app-setup.d.ts.map +1 -0
- package/dist/channels/linear/app-setup.js +102 -0
- package/dist/channels/linear/app-setup.js.map +1 -0
- package/dist/channels/linear/index.d.ts +5 -1
- package/dist/channels/linear/index.d.ts.map +1 -1
- package/dist/channels/linear/index.js +65 -94
- package/dist/channels/linear/index.js.map +1 -1
- package/dist/channels/linear/schema.d.ts +11 -25
- package/dist/channels/linear/schema.d.ts.map +1 -1
- package/dist/channels/linear/schema.js +6 -0
- package/dist/channels/linear/schema.js.map +1 -1
- package/dist/channels/linear/types.d.ts +37 -31
- package/dist/channels/linear/types.d.ts.map +1 -1
- package/dist/channels/messaging-registry.d.ts +16 -0
- package/dist/channels/messaging-registry.d.ts.map +1 -1
- package/dist/channels/messaging-registry.js +29 -0
- package/dist/channels/messaging-registry.js.map +1 -1
- package/dist/channels/reserved-connections.d.ts.map +1 -1
- package/dist/channels/reserved-connections.js +10 -0
- package/dist/channels/reserved-connections.js.map +1 -1
- package/dist/channels/resolve-user-endpoint.d.ts +34 -0
- package/dist/channels/resolve-user-endpoint.d.ts.map +1 -0
- package/dist/channels/resolve-user-endpoint.js +51 -0
- package/dist/channels/resolve-user-endpoint.js.map +1 -0
- package/dist/channels/resolve-user.d.ts +95 -0
- package/dist/channels/resolve-user.d.ts.map +1 -0
- package/dist/channels/resolve-user.js +143 -0
- package/dist/channels/resolve-user.js.map +1 -0
- package/dist/channels/run-input.d.ts +46 -4
- package/dist/channels/run-input.d.ts.map +1 -1
- package/dist/channels/run-input.js +94 -30
- package/dist/channels/run-input.js.map +1 -1
- package/dist/channels/runtime.d.ts +5 -2
- package/dist/channels/runtime.d.ts.map +1 -1
- package/dist/channels/runtime.js +19 -10
- package/dist/channels/runtime.js.map +1 -1
- package/dist/channels/schedule-delivery.d.ts +2 -13
- package/dist/channels/schedule-delivery.d.ts.map +1 -1
- package/dist/channels/schedule-delivery.js +9 -76
- package/dist/channels/schedule-delivery.js.map +1 -1
- package/dist/channels/slack/api.d.ts +2 -0
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +6 -0
- package/dist/channels/slack/api.js.map +1 -1
- package/dist/channels/slack/connections.d.ts +6 -0
- package/dist/channels/slack/connections.d.ts.map +1 -0
- package/dist/channels/slack/connections.js +6 -0
- package/dist/channels/slack/connections.js.map +1 -0
- package/dist/channels/slack/events.d.ts +278 -0
- package/dist/channels/slack/events.d.ts.map +1 -0
- package/dist/channels/slack/events.js +235 -0
- package/dist/channels/slack/events.js.map +1 -0
- package/dist/channels/slack/files.d.ts.map +1 -1
- package/dist/channels/slack/files.js +2 -3
- package/dist/channels/slack/files.js.map +1 -1
- package/dist/channels/slack/index.d.ts +90 -2
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +188 -6
- package/dist/channels/slack/index.js.map +1 -1
- package/dist/channels/slack/message-content.d.ts.map +1 -1
- package/dist/channels/slack/message-content.js +23 -28
- package/dist/channels/slack/message-content.js.map +1 -1
- package/dist/channels/slack/status.d.ts +76 -0
- package/dist/channels/slack/status.d.ts.map +1 -0
- package/dist/channels/slack/status.js +427 -0
- package/dist/channels/slack/status.js.map +1 -0
- package/dist/channels/trigger/client.d.ts.map +1 -1
- package/dist/channels/trigger/client.js +9 -11
- package/dist/channels/trigger/client.js.map +1 -1
- package/dist/channels/trigger/conversation.d.ts +11 -0
- package/dist/channels/trigger/conversation.d.ts.map +1 -0
- package/dist/channels/trigger/conversation.js +72 -0
- package/dist/channels/trigger/conversation.js.map +1 -0
- package/dist/channels/trigger/http.d.ts +130 -4
- package/dist/channels/trigger/http.d.ts.map +1 -1
- package/dist/channels/trigger/http.js +419 -82
- package/dist/channels/trigger/http.js.map +1 -1
- package/dist/channels/trigger/identity-context.d.ts +1 -1
- package/dist/channels/trigger/identity-context.d.ts.map +1 -1
- package/dist/channels/trigger/identity-context.js +3 -5
- package/dist/channels/trigger/identity-context.js.map +1 -1
- package/dist/channels/trigger/ingress.d.ts +70 -1
- package/dist/channels/trigger/ingress.d.ts.map +1 -1
- package/dist/channels/trigger/ingress.js +141 -9
- package/dist/channels/trigger/ingress.js.map +1 -1
- package/dist/channels/trigger/transport.d.ts +10 -0
- package/dist/channels/trigger/transport.d.ts.map +1 -1
- package/dist/channels/trigger/transport.js +25 -9
- package/dist/channels/trigger/transport.js.map +1 -1
- package/dist/channels/trigger/types.d.ts +92 -3
- package/dist/channels/trigger/types.d.ts.map +1 -1
- package/dist/channels/trigger/types.js +37 -0
- package/dist/channels/trigger/types.js.map +1 -1
- package/dist/channels/types.d.ts +53 -4
- package/dist/channels/types.d.ts.map +1 -1
- package/dist/channels/types.js +2 -0
- package/dist/channels/types.js.map +1 -1
- package/dist/concurrency/batch-processor.d.ts +51 -0
- package/dist/concurrency/batch-processor.d.ts.map +1 -0
- package/dist/concurrency/batch-processor.js +99 -0
- package/dist/concurrency/batch-processor.js.map +1 -0
- package/dist/connections.d.ts +5 -12
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +28 -30
- package/dist/connections.js.map +1 -1
- package/dist/connectors/mcp/langsmith-url.d.ts.map +1 -1
- package/dist/connectors/mcp/langsmith-url.js +0 -1
- package/dist/connectors/mcp/langsmith-url.js.map +1 -1
- package/dist/credential-gate.js +3 -3
- package/dist/credential-gate.js.map +1 -1
- package/dist/define-deep-agent.d.ts +2 -2
- package/dist/define-deep-agent.d.ts.map +1 -1
- package/dist/define-deep-agent.js +53 -2
- package/dist/define-deep-agent.js.map +1 -1
- package/dist/identity/index.d.ts.map +1 -1
- package/dist/identity/index.js +3 -1
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/loopback.d.ts +7 -2
- package/dist/identity/loopback.d.ts.map +1 -1
- package/dist/identity/loopback.js +15 -4
- package/dist/identity/loopback.js.map +1 -1
- package/dist/identity/options.d.ts +9 -0
- package/dist/identity/options.d.ts.map +1 -1
- package/dist/identity/options.js +1 -1
- package/dist/identity/options.js.map +1 -1
- package/dist/identity/slack/links.js +3 -2
- package/dist/identity/slack/links.js.map +1 -1
- package/dist/identity/types.d.ts +3 -0
- package/dist/identity/types.d.ts.map +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/ingress/index.d.ts +8 -0
- package/dist/ingress/index.d.ts.map +1 -1
- package/dist/ingress/index.js +32 -2
- package/dist/ingress/index.js.map +1 -1
- package/dist/ingress/loopback.d.ts +1 -0
- package/dist/ingress/loopback.d.ts.map +1 -1
- package/dist/ingress/loopback.js +7 -3
- package/dist/ingress/loopback.js.map +1 -1
- package/dist/ingress/runs.d.ts +27 -1
- package/dist/ingress/runs.d.ts.map +1 -1
- package/dist/ingress/runs.js +69 -6
- package/dist/ingress/runs.js.map +1 -1
- package/dist/managed-composition.d.ts +3 -0
- package/dist/managed-composition.d.ts.map +1 -1
- package/dist/managed-composition.js +29 -13
- package/dist/managed-composition.js.map +1 -1
- package/dist/memory/instructions-middleware.d.ts.map +1 -1
- package/dist/memory/instructions-middleware.js +6 -5
- package/dist/memory/instructions-middleware.js.map +1 -1
- package/dist/namespaces.d.ts +4 -21
- package/dist/namespaces.d.ts.map +1 -1
- package/dist/namespaces.js +0 -29
- package/dist/namespaces.js.map +1 -1
- package/dist/resilience/retry.d.ts +21 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +40 -0
- package/dist/resilience/retry.js.map +1 -0
- package/dist/runtime/async-subagents.d.ts +27 -0
- package/dist/runtime/async-subagents.d.ts.map +1 -0
- package/dist/runtime/async-subagents.js +139 -0
- package/dist/runtime/async-subagents.js.map +1 -0
- package/dist/runtime/auth.d.ts +1 -2
- package/dist/runtime/auth.d.ts.map +1 -1
- package/dist/runtime/auth.js +138 -72
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/backend.d.ts +9 -1
- package/dist/runtime/backend.d.ts.map +1 -1
- package/dist/runtime/backend.js +36 -11
- package/dist/runtime/backend.js.map +1 -1
- package/dist/runtime/browser-facade.d.ts +10 -0
- package/dist/runtime/browser-facade.d.ts.map +1 -0
- package/dist/runtime/browser-facade.js +23 -0
- package/dist/runtime/browser-facade.js.map +1 -0
- package/dist/runtime/browser-langsmith.d.ts +143 -0
- package/dist/runtime/browser-langsmith.d.ts.map +1 -0
- package/dist/runtime/browser-langsmith.js +507 -0
- package/dist/runtime/browser-langsmith.js.map +1 -0
- package/dist/runtime/browser-recorder.py +831 -0
- package/dist/runtime/browser-selection.d.ts +10 -0
- package/dist/runtime/browser-selection.d.ts.map +1 -0
- package/dist/runtime/browser-selection.js +21 -0
- package/dist/runtime/browser-selection.js.map +1 -0
- package/dist/runtime/browser.d.ts +138 -0
- package/dist/runtime/browser.d.ts.map +1 -0
- package/dist/runtime/browser.js +802 -0
- package/dist/runtime/browser.js.map +1 -0
- package/dist/runtime/channel-icon.d.ts.map +1 -1
- package/dist/runtime/channel-icon.js +18 -7
- package/dist/runtime/channel-icon.js.map +1 -1
- package/dist/runtime/channel.d.ts +5 -0
- package/dist/runtime/channel.d.ts.map +1 -1
- package/dist/runtime/channel.js.map +1 -1
- package/dist/runtime/graph-build-timing.d.ts +30 -0
- package/dist/runtime/graph-build-timing.d.ts.map +1 -0
- package/dist/runtime/graph-build-timing.js +50 -0
- package/dist/runtime/graph-build-timing.js.map +1 -0
- package/dist/runtime/http.d.ts +15 -0
- package/dist/runtime/http.d.ts.map +1 -1
- package/dist/runtime/http.js +37 -0
- package/dist/runtime/http.js.map +1 -1
- package/dist/runtime/identity-http.d.ts.map +1 -1
- package/dist/runtime/identity-http.js +19 -7
- package/dist/runtime/identity-http.js.map +1 -1
- package/dist/runtime/identity-runtime.d.ts +4 -9
- package/dist/runtime/identity-runtime.d.ts.map +1 -1
- package/dist/runtime/identity-runtime.js +12 -25
- package/dist/runtime/identity-runtime.js.map +1 -1
- package/dist/runtime/index.d.ts +38 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +104 -52
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/langsmith-env.d.ts +19 -0
- package/dist/runtime/langsmith-env.d.ts.map +1 -0
- package/dist/runtime/langsmith-env.js +38 -0
- package/dist/runtime/langsmith-env.js.map +1 -0
- package/dist/runtime/log.d.ts +8 -14
- package/dist/runtime/log.d.ts.map +1 -1
- package/dist/runtime/log.js +16 -7
- package/dist/runtime/log.js.map +1 -1
- package/dist/runtime/managed-middleware.d.ts.map +1 -1
- package/dist/runtime/managed-middleware.js +1 -14
- package/dist/runtime/managed-middleware.js.map +1 -1
- package/dist/runtime/managed-thread.d.ts +61 -0
- package/dist/runtime/managed-thread.d.ts.map +1 -0
- package/dist/runtime/managed-thread.js +76 -0
- package/dist/runtime/managed-thread.js.map +1 -0
- package/dist/runtime/managed-tools.d.ts +18 -2
- package/dist/runtime/managed-tools.d.ts.map +1 -1
- package/dist/runtime/managed-tools.js +26 -22
- package/dist/runtime/managed-tools.js.map +1 -1
- package/dist/runtime/memory/mounts.d.ts +82 -11
- package/dist/runtime/memory/mounts.d.ts.map +1 -1
- package/dist/runtime/memory/mounts.js +173 -34
- package/dist/runtime/memory/mounts.js.map +1 -1
- package/dist/runtime/memory/policy.d.ts.map +1 -1
- package/dist/runtime/memory/policy.js +1 -3
- package/dist/runtime/memory/policy.js.map +1 -1
- package/dist/runtime/parent-run.d.ts +33 -0
- package/dist/runtime/parent-run.d.ts.map +1 -0
- package/dist/runtime/parent-run.js +114 -0
- package/dist/runtime/parent-run.js.map +1 -0
- package/dist/runtime/run-input.d.ts +14 -1
- package/dist/runtime/run-input.d.ts.map +1 -1
- package/dist/runtime/run-input.js +118 -7
- package/dist/runtime/run-input.js.map +1 -1
- package/dist/runtime/sandbox-manager.d.ts +31 -17
- package/dist/runtime/sandbox-manager.d.ts.map +1 -1
- package/dist/runtime/sandbox-manager.js +112 -70
- package/dist/runtime/sandbox-manager.js.map +1 -1
- package/dist/runtime/schedule-auth.d.ts +79 -0
- package/dist/runtime/schedule-auth.d.ts.map +1 -1
- package/dist/runtime/schedule-auth.js +165 -7
- package/dist/runtime/schedule-auth.js.map +1 -1
- package/dist/runtime/selected-skills-backend.d.ts +3 -3
- package/dist/runtime/selected-skills-backend.d.ts.map +1 -1
- package/dist/runtime/selected-skills-backend.js +5 -5
- package/dist/runtime/selected-skills-backend.js.map +1 -1
- package/dist/runtime/static-entry.d.ts.map +1 -1
- package/dist/runtime/static-entry.js +1 -0
- package/dist/runtime/static-entry.js.map +1 -1
- package/dist/runtime/thread-record.d.ts +88 -0
- package/dist/runtime/thread-record.d.ts.map +1 -0
- package/dist/runtime/thread-record.js +213 -0
- package/dist/runtime/thread-record.js.map +1 -0
- package/dist/runtime/types.d.ts +12 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime-schedules.d.ts +15 -0
- package/dist/runtime-schedules.d.ts.map +1 -1
- package/dist/runtime-schedules.js +85 -23
- package/dist/runtime-schedules.js.map +1 -1
- package/dist/sandbox.d.ts +0 -6
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +3 -7
- package/dist/sandbox.js.map +1 -1
- package/dist/schedule-channel.d.ts +5 -2
- package/dist/schedule-channel.d.ts.map +1 -1
- package/dist/schedule-channel.js +13 -12
- package/dist/schedule-channel.js.map +1 -1
- package/dist/telemetry/lifecycle.d.ts +26 -0
- package/dist/telemetry/lifecycle.d.ts.map +1 -0
- package/dist/telemetry/lifecycle.js +49 -0
- package/dist/telemetry/lifecycle.js.map +1 -0
- package/dist/telemetry/metadata.d.ts.map +1 -1
- package/dist/telemetry/metadata.js +4 -4
- package/dist/telemetry/metadata.js.map +1 -1
- package/dist/telemetry/otel/context.d.ts +57 -0
- package/dist/telemetry/otel/context.d.ts.map +1 -0
- package/dist/telemetry/otel/context.js +122 -0
- package/dist/telemetry/otel/context.js.map +1 -0
- package/dist/telemetry/otel/exporter.d.ts +53 -0
- package/dist/telemetry/otel/exporter.d.ts.map +1 -0
- package/dist/telemetry/otel/exporter.js +190 -0
- package/dist/telemetry/otel/exporter.js.map +1 -0
- package/dist/telemetry/otel/index.d.ts +6 -0
- package/dist/telemetry/otel/index.d.ts.map +1 -0
- package/dist/telemetry/otel/index.js +3 -0
- package/dist/telemetry/otel/index.js.map +1 -0
- package/dist/telemetry/otel/otlp.d.ts +44 -0
- package/dist/telemetry/otel/otlp.d.ts.map +1 -0
- package/dist/telemetry/otel/otlp.js +7 -0
- package/dist/telemetry/otel/otlp.js.map +1 -0
- package/dist/telemetry/otel/truncate.d.ts +10 -0
- package/dist/telemetry/otel/truncate.d.ts.map +1 -0
- package/dist/telemetry/otel/truncate.js +39 -0
- package/dist/telemetry/otel/truncate.js.map +1 -0
- package/dist/telemetry/run-listener.d.ts +1 -1
- package/dist/telemetry/run-listener.d.ts.map +1 -1
- package/dist/telemetry/run-listener.js +32 -2
- package/dist/telemetry/run-listener.js.map +1 -1
- package/dist/telemetry/transport/posthog.d.ts +13 -1
- package/dist/telemetry/transport/posthog.d.ts.map +1 -1
- package/dist/telemetry/transport/posthog.js +68 -30
- package/dist/telemetry/transport/posthog.js.map +1 -1
- package/dist/types.d.ts +19 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/values.d.ts +15 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +31 -0
- package/dist/values.js.map +1 -0
- package/package.json +26 -12
- package/dist/channels/http/forward.d.ts +0 -13
- package/dist/channels/http/forward.d.ts.map +0 -1
- package/dist/channels/http/forward.js +0 -128
- package/dist/channels/http/forward.js.map +0 -1
- package/dist/channels/http/reply.d.ts +0 -20
- package/dist/channels/http/reply.d.ts.map +0 -1
- package/dist/channels/http/reply.js +0 -116
- package/dist/channels/http/reply.js.map +0 -1
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import { INTERRUPT } from "@langchain/langgraph";
|
|
2
|
-
import {
|
|
2
|
+
import { bindingWithMessages } from "../binding.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { extractAssistantText } from "../assistant-text.js";
|
|
4
|
+
import { missingWorkspaceConnectionSlug, } from "../../agent-auth.js";
|
|
5
|
+
import { resolveExternalPrincipalId } from "../../connections.js";
|
|
7
6
|
import { DEFAULT_REACTION_EMOJI, resolveReactionEmoji, } from "../reactions.js";
|
|
7
|
+
import { setLogAttributes } from "../../telemetry/otel/index.js";
|
|
8
8
|
import { logger } from "../../runtime/log.js";
|
|
9
9
|
import { INTERRUPT_CORRELATION_KEY } from "../../run-context.js";
|
|
10
|
-
import { ingressThreadInterrupts, observeIngressAgent, resumeIngressAgent, startIngressAgent, } from "./ingress.js";
|
|
10
|
+
import { cancelIngressThreadRuns, conversationThreadId, ingressThreadExists, ingressResumeTarget, ingressThreadInterrupts, newerIngressRun, observeIngressAgent, resumeIngressAgent, startIngressAgent, } from "./ingress.js";
|
|
11
11
|
import { scheduleIngressWork } from "../../ingress/index.js";
|
|
12
|
+
import { lookupStatus, rejectedAsBusy, } from "../../ingress/runs.js";
|
|
13
|
+
import { runStartOptions } from "../run-input.js";
|
|
12
14
|
import { createTriggerClient, LANGSMITH_MDA_TRIGGER_SERVER_URL_ENV, TriggerClientError, } from "./client.js";
|
|
13
15
|
import { IdentityContextUnavailableError, InvalidIdentityContextError, principalIdFromIdentityContext, } from "./identity-context.js";
|
|
14
16
|
import { resolveTracerSessionId } from "./tracing-project.js";
|
|
15
|
-
import {
|
|
17
|
+
import { normalizeUuid } from "./uuid.js";
|
|
18
|
+
import { postReply, resolveChannelUser, } from "../resolve-user.js";
|
|
19
|
+
import { createTriggerTransport } from "./transport.js";
|
|
20
|
+
import { parseTriggerChannelEvent, triggerChannelBinding, TRIGGER_SERVICE_KEY_HEADER, normalizedUserPromptResponse, triggerEventActor, } from "./types.js";
|
|
21
|
+
import { isRecord, nonblankString } from "../../values.js";
|
|
16
22
|
export { TRIGGER_SERVICE_KEY_HEADER } from "./types.js";
|
|
17
23
|
export const ASSISTANT_ID_ENV = "MDA_ASSISTANT_ID";
|
|
18
24
|
// Raised when the thread cannot say which interrupt an answer belongs to. An
|
|
@@ -30,6 +36,37 @@ async function resolveEventPrincipal(event, verify) {
|
|
|
30
36
|
}
|
|
31
37
|
return await principalIdFromIdentityContext(token, verify);
|
|
32
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* The delivery's actor when Agent Auth keys it on the signed principal.
|
|
41
|
+
* Trigger Server does not sign `actor`, so one that does not match is dropped.
|
|
42
|
+
*/
|
|
43
|
+
async function verifiedEventActor(event, principalId, resolvePrincipal) {
|
|
44
|
+
const actor = triggerEventActor(event);
|
|
45
|
+
const team = slackInstallTeam(event.source_thread_key);
|
|
46
|
+
if (actor?.provider !== "slack" || !team)
|
|
47
|
+
return undefined;
|
|
48
|
+
try {
|
|
49
|
+
const resolved = await resolvePrincipal({
|
|
50
|
+
provider: "slack",
|
|
51
|
+
issuer: team,
|
|
52
|
+
subject: actor.id,
|
|
53
|
+
});
|
|
54
|
+
if (normalizeUuid(resolved) === principalId)
|
|
55
|
+
return actor;
|
|
56
|
+
logger.warn("channel actor does not match identity_context");
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
logger.warn(`channel actor unverified (${logger.safeErrorLabel(error)})`);
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/** The workspace the Slack app is installed in, which keys its users' principals. */
|
|
64
|
+
function slackInstallTeam(sourceThreadKey) {
|
|
65
|
+
const [provider, version, , team] = sourceThreadKey.split(":");
|
|
66
|
+
return provider === "slack" && version === "v1"
|
|
67
|
+
? nonblankString(team)
|
|
68
|
+
: undefined;
|
|
69
|
+
}
|
|
33
70
|
/** Validate one Trigger message, start its run, and enqueue observation. */
|
|
34
71
|
export async function handleTriggerChannelEventRequest(request, options) {
|
|
35
72
|
if (!request.headers.get(TRIGGER_SERVICE_KEY_HEADER)?.trim()) {
|
|
@@ -58,7 +95,7 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
58
95
|
return Response.json({ error: "missing channel identity_context" }, { status: 400 });
|
|
59
96
|
}
|
|
60
97
|
if (error instanceof IdentityContextUnavailableError) {
|
|
61
|
-
logger.error(`channel identity_context unavailable (${logger.safeErrorLabel(error)})
|
|
98
|
+
logger.error(`channel identity_context unavailable (${logger.safeErrorLabel(error)})`, error);
|
|
62
99
|
return Response.json({ error: "identity_context verification unavailable" }, { status: 503 });
|
|
63
100
|
}
|
|
64
101
|
if (error instanceof InvalidIdentityContextError) {
|
|
@@ -67,7 +104,19 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
67
104
|
}
|
|
68
105
|
throw error;
|
|
69
106
|
}
|
|
107
|
+
setLogAttributes({
|
|
108
|
+
event_type: event.type,
|
|
109
|
+
event_id: event.event_id,
|
|
110
|
+
delivery_id: event.delivery_id,
|
|
111
|
+
channel_id: event.channel_id,
|
|
112
|
+
});
|
|
70
113
|
logger.info(`Channel incoming event (type=${event.type}, event_id=${logger.logIdentifier(event.event_id)}, delivery_id=${logger.logIdentifier(event.delivery_id)}, channel_id=${logger.logIdentifier(event.channel_id)})`);
|
|
114
|
+
if (event.type === "run_cancel") {
|
|
115
|
+
return await cancelEventRuns(event, userId, options);
|
|
116
|
+
}
|
|
117
|
+
const resolvePrincipal = options.resolvePrincipal ?? resolveExternalPrincipalId;
|
|
118
|
+
/** Who the delivery came from; never logged. */
|
|
119
|
+
const actor = await verifiedEventActor(event, userId, resolvePrincipal);
|
|
71
120
|
let client = options.triggerClient;
|
|
72
121
|
if (!client) {
|
|
73
122
|
try {
|
|
@@ -75,11 +124,11 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
75
124
|
userId: request.headers.get("x-user-id") ?? undefined,
|
|
76
125
|
});
|
|
77
126
|
if (!client) {
|
|
78
|
-
logger.error(`channel transport is not configured (${LANGSMITH_MDA_TRIGGER_SERVER_URL_ENV} and LANGSMITH_API_KEY are required)`);
|
|
127
|
+
logger.error(`channel transport is not configured (${LANGSMITH_MDA_TRIGGER_SERVER_URL_ENV} and LANGSMITH_API_KEY or LANGCHAIN_API_KEY are required)`);
|
|
79
128
|
}
|
|
80
129
|
}
|
|
81
130
|
catch (error) {
|
|
82
|
-
logger.error(`channel transport is not configured (${logger.safeErrorLabel(error)})
|
|
131
|
+
logger.error(`channel transport is not configured (${logger.safeErrorLabel(error)})`, error);
|
|
83
132
|
client = undefined;
|
|
84
133
|
}
|
|
85
134
|
}
|
|
@@ -91,10 +140,94 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
91
140
|
logger.error(`${ASSISTANT_ID_ENV} is not configured`);
|
|
92
141
|
return Response.json({ error: "channel runtime is not configured" }, { status: 500 });
|
|
93
142
|
}
|
|
143
|
+
let user;
|
|
144
|
+
try {
|
|
145
|
+
user = await resolveChannelUser(options.resolveUser, actor, options.channelName, event.delivery_id, resolvePrincipal);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
logger.error(`channel resolveUser failed (${logger.safeErrorLabel(error)})`);
|
|
149
|
+
return Response.json({ error: "channel user resolution failed" }, { status: 500 });
|
|
150
|
+
}
|
|
151
|
+
if (user?.type === "principal")
|
|
152
|
+
userId = user.id;
|
|
153
|
+
/** `resolveUser`'s answer when it holds back the run the delivery would start. */
|
|
154
|
+
const withheld = user?.type === "principal" ? undefined : user;
|
|
155
|
+
/** Post `resolveUser`'s reply, if any, instead of that run. */
|
|
156
|
+
const withhold = async () => {
|
|
157
|
+
if (withheld?.type === "reply")
|
|
158
|
+
await postReply(withheld.message, {
|
|
159
|
+
name: options.channelName,
|
|
160
|
+
provider: options.sourceProvider,
|
|
161
|
+
target: triggerTarget(event),
|
|
162
|
+
transport: createTriggerTransport(client, {
|
|
163
|
+
actionId: event.delivery_id,
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
logNoRun(event, { type: "skipped" });
|
|
167
|
+
};
|
|
168
|
+
const observe = (started) => observeAcceptedRun({
|
|
169
|
+
event,
|
|
170
|
+
started,
|
|
171
|
+
client,
|
|
172
|
+
observeAgent: options.observeAgent,
|
|
173
|
+
sourceProvider: options.sourceProvider,
|
|
174
|
+
sourceThreadKey: event.source_thread_key,
|
|
175
|
+
userId,
|
|
176
|
+
reactions: options.reactions ?? DEFAULT_REACTION_EMOJI,
|
|
177
|
+
...(options.startedStatus && { startedStatus: options.startedStatus }),
|
|
178
|
+
multitaskStrategy: options.multitaskStrategy,
|
|
179
|
+
newerRun: options.newerRun,
|
|
180
|
+
});
|
|
181
|
+
let threadId;
|
|
182
|
+
try {
|
|
183
|
+
threadId = await (options.conversationThread ?? conversationThreadId)({
|
|
184
|
+
sourceProvider: options.sourceProvider,
|
|
185
|
+
sourceThreadKey: event.source_thread_key,
|
|
186
|
+
userId,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
logger.error(`channel thread could not be found (${logger.safeErrorLabel(error)})`);
|
|
191
|
+
return Response.json({ error: "channel run could not be started" }, { status: 500 });
|
|
192
|
+
}
|
|
193
|
+
const thread = { id: threadId, sourceThreadKey: event.source_thread_key };
|
|
194
|
+
/**
|
|
195
|
+
* Whether the delivery starts a turn of its own, which finishes: a message,
|
|
196
|
+
* or a prompt response that answers no interrupt. Resumes don't.
|
|
197
|
+
*/
|
|
198
|
+
let startsTurn = event.type === "message";
|
|
199
|
+
/** Tell the provider a turn is done, once; a failure is logged. */
|
|
200
|
+
const finish = async (finished) => {
|
|
201
|
+
if (!startsTurn || !options.onFinish)
|
|
202
|
+
return;
|
|
203
|
+
const { identity_context: _token, ...message } = event;
|
|
204
|
+
const raw = {
|
|
205
|
+
delivery: message,
|
|
206
|
+
// Strings only, so JSON as the delivery's `rawEvent` is.
|
|
207
|
+
...(actor && { actor: { ...actor } }),
|
|
208
|
+
};
|
|
209
|
+
try {
|
|
210
|
+
await options.onFinish(triggerTarget(event), {
|
|
211
|
+
threadId: thread.id,
|
|
212
|
+
rawEvent: raw,
|
|
213
|
+
...finished,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
logger.error(`channel finish notice failed (${logger.safeErrorLabel(error)})`);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const finishLater = (finished) => {
|
|
221
|
+
if (options.onFinish)
|
|
222
|
+
scheduleIngressWork(() => finish(finished), {
|
|
223
|
+
label: "Channel finish notice",
|
|
224
|
+
schedule: options.schedule,
|
|
225
|
+
});
|
|
226
|
+
};
|
|
94
227
|
let started;
|
|
95
228
|
try {
|
|
96
229
|
const common = {
|
|
97
|
-
threadId:
|
|
230
|
+
threadId: thread.id,
|
|
98
231
|
assistantId,
|
|
99
232
|
sourceProvider: options.sourceProvider,
|
|
100
233
|
sourceThreadKey: event.source_thread_key,
|
|
@@ -102,19 +235,113 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
102
235
|
context: {},
|
|
103
236
|
binding: triggerChannelBinding(event, options.sourceProvider, options.channelName),
|
|
104
237
|
};
|
|
238
|
+
/**
|
|
239
|
+
* Start the delivery's run as `route` decides: at once, in the
|
|
240
|
+
* background, or not at all. The answer for Trigger Server when it has
|
|
241
|
+
* one already, otherwise the run it started.
|
|
242
|
+
*/
|
|
243
|
+
const decideAndStart = async (route, undecided) => {
|
|
244
|
+
/** Start the run; `undefined` when `reject` left the thread to its run. */
|
|
245
|
+
const startRun = async (input) => {
|
|
246
|
+
const strategy = options.multitaskStrategy;
|
|
247
|
+
try {
|
|
248
|
+
return await (options.startAgent ?? startIngressAgent)({
|
|
249
|
+
...common,
|
|
250
|
+
...(input
|
|
251
|
+
? decidedRun(input, common.binding)
|
|
252
|
+
: { messages: undecided() }),
|
|
253
|
+
...(strategy && { multitaskStrategy: strategy }),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
// A run already active on the thread keeps it under `reject`.
|
|
258
|
+
if (rejectedAsBusy(strategy, error)) {
|
|
259
|
+
logger.info(`channel ${event.type} rejected: its thread is busy (delivery_id=${logger.logIdentifier(event.delivery_id)})`);
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
if (route?.type === "background") {
|
|
266
|
+
// Trigger Server only waits briefly, so it hears first; a failure
|
|
267
|
+
// from here on is logged, and nothing redelivers the event.
|
|
268
|
+
scheduleIngressWork(async () => {
|
|
269
|
+
const decided = await route.decide();
|
|
270
|
+
if (decided.type !== "input") {
|
|
271
|
+
logNoRun(event, decided);
|
|
272
|
+
return finish(skipped("ignored"));
|
|
273
|
+
}
|
|
274
|
+
if (withheld) {
|
|
275
|
+
await withhold();
|
|
276
|
+
return finish(skipped("ignored"));
|
|
277
|
+
}
|
|
278
|
+
let run;
|
|
279
|
+
try {
|
|
280
|
+
run = await startRun(decided.input);
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
logger.error(`channel run could not be started (${logger.safeErrorLabel(error)})`, error);
|
|
284
|
+
return finish({
|
|
285
|
+
type: "failed",
|
|
286
|
+
reason: "start",
|
|
287
|
+
interrupts: [],
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
await finish(run ? await observe(run) : skipped("rejected"));
|
|
291
|
+
}, { label: "Channel event decision", schedule: options.schedule });
|
|
292
|
+
return acceptedResponse(event);
|
|
293
|
+
}
|
|
294
|
+
if (route?.type === "skipped") {
|
|
295
|
+
logNoRun(event, route);
|
|
296
|
+
finishLater(skipped("ignored"));
|
|
297
|
+
return acceptedResponse(event);
|
|
298
|
+
}
|
|
299
|
+
// Trigger Server may deliver it again, which finishes on its own.
|
|
300
|
+
if (route?.type === "failed")
|
|
301
|
+
return startFailedResponse();
|
|
302
|
+
if (withheld) {
|
|
303
|
+
await withhold();
|
|
304
|
+
finishLater(skipped("ignored"));
|
|
305
|
+
return acceptedResponse(event);
|
|
306
|
+
}
|
|
307
|
+
const run = await startRun(route?.input);
|
|
308
|
+
if (!run) {
|
|
309
|
+
finishLater(skipped("rejected"));
|
|
310
|
+
return acceptedResponse(event);
|
|
311
|
+
}
|
|
312
|
+
return run;
|
|
313
|
+
};
|
|
105
314
|
switch (event.type) {
|
|
106
|
-
case "message":
|
|
107
|
-
|
|
315
|
+
case "message": {
|
|
316
|
+
const message = event;
|
|
317
|
+
if (!(await mayStartIn(common, message, options))) {
|
|
318
|
+
logger.info(`channel message started no run: the agent never ran on its thread (delivery_id=${logger.logIdentifier(message.delivery_id)})`);
|
|
319
|
+
finishLater(skipped("ignored"));
|
|
320
|
+
return acceptedResponse(message);
|
|
321
|
+
}
|
|
322
|
+
const outcome = await decideAndStart(await options.decideMessage?.(message, thread, actor), () => options.messageInput?.(message) ?? message.input.messages);
|
|
323
|
+
if (outcome instanceof Response)
|
|
324
|
+
return outcome;
|
|
325
|
+
started = outcome;
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
case "interrupt_resume": {
|
|
329
|
+
if (withheld) {
|
|
330
|
+
await withhold();
|
|
331
|
+
return acceptedResponse(event);
|
|
332
|
+
}
|
|
333
|
+
// The answer may belong to a paused async subagent.
|
|
334
|
+
const target = await (options.resumeTarget ?? ingressResumeTarget)({
|
|
108
335
|
...common,
|
|
109
|
-
|
|
336
|
+
interruptIds: Object.keys(event.interaction.resume),
|
|
110
337
|
});
|
|
111
|
-
break;
|
|
112
|
-
case "interrupt_resume":
|
|
113
338
|
started = await (options.resumeAgent ?? resumeIngressAgent)({
|
|
114
339
|
...common,
|
|
340
|
+
...target,
|
|
115
341
|
resume: event.interaction.resume,
|
|
116
342
|
});
|
|
117
343
|
break;
|
|
344
|
+
}
|
|
118
345
|
case "user_prompt_response": {
|
|
119
346
|
const normalized = normalizedUserPromptResponse(event);
|
|
120
347
|
const interruptId = await interruptAnsweredBy({
|
|
@@ -125,16 +352,23 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
125
352
|
correlationId: normalized.correlation_id,
|
|
126
353
|
threadInterrupts: options.threadInterrupts,
|
|
127
354
|
});
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
355
|
+
if (interruptId !== undefined) {
|
|
356
|
+
if (withheld) {
|
|
357
|
+
await withhold();
|
|
358
|
+
return acceptedResponse(event);
|
|
359
|
+
}
|
|
360
|
+
started = await (options.resumeAgent ?? resumeIngressAgent)({
|
|
361
|
+
...common,
|
|
362
|
+
resume: { [interruptId]: normalized },
|
|
363
|
+
});
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
// A fresh turn, which the provider may decide, and which finishes.
|
|
367
|
+
startsTurn = true;
|
|
368
|
+
const outcome = await decideAndStart(await options.decideInteraction?.(event, thread, actor), () => []);
|
|
369
|
+
if (outcome instanceof Response)
|
|
370
|
+
return outcome;
|
|
371
|
+
started = outcome;
|
|
138
372
|
break;
|
|
139
373
|
}
|
|
140
374
|
default: {
|
|
@@ -149,24 +383,87 @@ export async function handleTriggerChannelEventRequest(request, options) {
|
|
|
149
383
|
logger.warn(`channel user prompt response could not be matched to an interrupt (${error.message}, delivery_id=${logger.logIdentifier(event.delivery_id)}, event_id=${logger.logIdentifier(event.event_id)})`);
|
|
150
384
|
return acceptedResponse(event);
|
|
151
385
|
}
|
|
152
|
-
logger.error(`channel run could not be started (${logger.safeErrorLabel(error)})
|
|
153
|
-
return
|
|
386
|
+
logger.error(`channel run could not be started (${logger.safeErrorLabel(error)})`, error);
|
|
387
|
+
return startFailedResponse();
|
|
154
388
|
}
|
|
155
|
-
scheduleIngressWork(() =>
|
|
156
|
-
event,
|
|
157
|
-
started,
|
|
158
|
-
client,
|
|
159
|
-
observeAgent: options.observeAgent,
|
|
160
|
-
sourceProvider: options.sourceProvider,
|
|
161
|
-
sourceThreadKey: event.source_thread_key,
|
|
162
|
-
userId,
|
|
163
|
-
reactions: options.reactions ?? DEFAULT_REACTION_EMOJI,
|
|
164
|
-
}), {
|
|
389
|
+
scheduleIngressWork(async () => finish(await observe(started)), {
|
|
165
390
|
label: "Channel run observation",
|
|
166
391
|
schedule: options.schedule,
|
|
167
392
|
});
|
|
168
393
|
return acceptedResponse(event);
|
|
169
394
|
}
|
|
395
|
+
/** Where a delivery's replies go, as the channel binding names it. */
|
|
396
|
+
function triggerTarget(event) {
|
|
397
|
+
return {
|
|
398
|
+
channel_id: event.channel_id,
|
|
399
|
+
address: event.address,
|
|
400
|
+
source_thread_key: event.source_thread_key,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
function skipped(reason) {
|
|
404
|
+
return { type: "skipped", reason, interrupts: [] };
|
|
405
|
+
}
|
|
406
|
+
/** Log an event that started no run; a failed handler logged its own error. */
|
|
407
|
+
function logNoRun(event, decision) {
|
|
408
|
+
logger.info(`channel ${event.type} started no run (${decision.type === "failed" ? "its handler failed, " : ""}delivery_id=${logger.logIdentifier(event.delivery_id)})`);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* A decided run's start options. Its messages replace the delivery's in the
|
|
412
|
+
* binding, as the run's own input; its context sits beside the binding.
|
|
413
|
+
*/
|
|
414
|
+
function decidedRun(input, binding) {
|
|
415
|
+
return {
|
|
416
|
+
...runStartOptions(input),
|
|
417
|
+
binding: bindingWithMessages(binding, input.messages),
|
|
418
|
+
context: input.context ?? {},
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function startFailedResponse() {
|
|
422
|
+
return Response.json({ error: "channel run could not be started" }, { status: 500 });
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Stop the source thread's runs; each run's observer reports `run.cancelled`.
|
|
426
|
+
*
|
|
427
|
+
* Runs are cancelled as the thread's channel principal, so the managed owner
|
|
428
|
+
* filter confines the cancel to this source conversation.
|
|
429
|
+
*/
|
|
430
|
+
async function cancelEventRuns(event, userId, options) {
|
|
431
|
+
let cancelled;
|
|
432
|
+
try {
|
|
433
|
+
cancelled = await (options.cancelRuns ?? cancelIngressThreadRuns)({
|
|
434
|
+
threadId: await (options.conversationThread ?? conversationThreadId)({
|
|
435
|
+
sourceProvider: options.sourceProvider,
|
|
436
|
+
sourceThreadKey: event.source_thread_key,
|
|
437
|
+
userId,
|
|
438
|
+
}),
|
|
439
|
+
sourceProvider: options.sourceProvider,
|
|
440
|
+
sourceThreadKey: event.source_thread_key,
|
|
441
|
+
userId,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
logger.error(`channel runs could not be cancelled (${logger.safeErrorLabel(error)})`);
|
|
446
|
+
return Response.json({ error: "channel runs could not be cancelled" }, { status: 500 });
|
|
447
|
+
}
|
|
448
|
+
logger.info(`Channel runs cancelled (count=${cancelled}, delivery_id=${logger.logIdentifier(event.delivery_id)})`);
|
|
449
|
+
return acceptedResponse(event);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Whether a message may start a run on its thread: always, unless it may only
|
|
453
|
+
* continue a thread the agent already ran on and none ran there. A failed
|
|
454
|
+
* lookup is logged and lets it start, as before the check.
|
|
455
|
+
*/
|
|
456
|
+
async function mayStartIn(common, event, options) {
|
|
457
|
+
if (!(await options.onlyContinuesThread?.(event)))
|
|
458
|
+
return true;
|
|
459
|
+
try {
|
|
460
|
+
return await (options.threadExists ?? ingressThreadExists)(common);
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
logger.warn(`channel thread lookup failed; the message starts as before (${logger.safeErrorLabel(error)})`);
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
170
467
|
function acceptedResponse(event) {
|
|
171
468
|
return Response.json({ status: "accepted", delivery_id: event.delivery_id }, { status: 202 });
|
|
172
469
|
}
|
|
@@ -194,27 +491,63 @@ async function interruptAnsweredBy(input) {
|
|
|
194
491
|
}
|
|
195
492
|
return undefined;
|
|
196
493
|
}
|
|
197
|
-
|
|
494
|
+
// A tool-call review is answered from its own prompt (`interrupt_resume`):
|
|
495
|
+
// a click on one of the agent's buttons, such as a rating, is no decision.
|
|
496
|
+
const answerable = pending.filter((candidate) => !isToolCallReview(candidate.value));
|
|
497
|
+
if (answerable.length > 1) {
|
|
198
498
|
// Interrupt ids carry no ordering, so without a correlation id there is
|
|
199
499
|
// nothing to choose by.
|
|
200
|
-
throw new AmbiguousInterruptError(`${
|
|
500
|
+
throw new AmbiguousInterruptError(`${answerable.length} interrupts pending`);
|
|
501
|
+
}
|
|
502
|
+
if (answerable.length === 0 && pending.length > 0) {
|
|
503
|
+
// Starting a turn here would abandon the review.
|
|
504
|
+
throw new AmbiguousInterruptError("the thread waits on a tool-call review, which a click doesn't answer");
|
|
201
505
|
}
|
|
202
|
-
return
|
|
506
|
+
return answerable[0]?.id;
|
|
507
|
+
}
|
|
508
|
+
/** Whether an interrupt is a tool-call review, as `humanInTheLoopMiddleware` raises one. */
|
|
509
|
+
function isToolCallReview(value) {
|
|
510
|
+
return isRecord(value) && Array.isArray(value.action_requests);
|
|
203
511
|
}
|
|
204
512
|
function interruptCorrelationId(value) {
|
|
205
513
|
if (!isRecord(value))
|
|
206
514
|
return undefined;
|
|
207
|
-
|
|
208
|
-
return typeof id === "string" && id.trim() ? id : undefined;
|
|
515
|
+
return nonblankString(value[INTERRUPT_CORRELATION_KEY]);
|
|
209
516
|
}
|
|
210
517
|
async function observeAcceptedRun(input) {
|
|
211
518
|
const { event, started, client } = input;
|
|
212
|
-
const
|
|
519
|
+
const run = {
|
|
520
|
+
threadId: started.threadId,
|
|
521
|
+
runId: started.runId,
|
|
522
|
+
sourceProvider: input.sourceProvider,
|
|
523
|
+
sourceThreadKey: input.sourceThreadKey,
|
|
524
|
+
userId: input.userId,
|
|
525
|
+
};
|
|
526
|
+
// Only these strategies let a newer message cancel a run.
|
|
527
|
+
const replaceable = input.multitaskStrategy === "interrupt" ||
|
|
528
|
+
input.multitaskStrategy === "rollback";
|
|
529
|
+
/**
|
|
530
|
+
* A newer message's run took the thread over; it reports to Slack, so this
|
|
531
|
+
* run says nothing that would stop or fail the thread's status. It ended
|
|
532
|
+
* `interrupted`, as the HTTP channel reports a replaced run.
|
|
533
|
+
*/
|
|
534
|
+
const replaced = () => {
|
|
535
|
+
logger.info(`channel run was replaced by a newer message (delivery_id=${logger.logIdentifier(event.delivery_id)}, run_id=${logger.logIdentifier(started.runId)})`);
|
|
536
|
+
return {
|
|
537
|
+
type: "run",
|
|
538
|
+
run: { id: started.runId, status: "interrupted" },
|
|
539
|
+
interrupts: [],
|
|
540
|
+
};
|
|
541
|
+
};
|
|
542
|
+
const lifecycle = async (type, message, status) => {
|
|
213
543
|
logger.info(`Channel outgoing event (type=${type}, delivery_id=${logger.logIdentifier(event.delivery_id)}, channel_id=${logger.logIdentifier(event.channel_id)}, run_id=${logger.logIdentifier(started.runId)})`);
|
|
214
|
-
const request =
|
|
544
|
+
const request = {
|
|
545
|
+
...runtimeEvent(type, event, started, message, await resolveTracerSessionId()),
|
|
546
|
+
...status,
|
|
547
|
+
};
|
|
215
548
|
return bestEffort(client.postRuntimeEvent(event.channel_id, request));
|
|
216
549
|
};
|
|
217
|
-
await lifecycle("run.started");
|
|
550
|
+
await lifecycle("run.started", undefined, input.startedStatus);
|
|
218
551
|
// Not awaited here, so the reaction never delays the reply. The `finally`
|
|
219
552
|
// settles it so it cannot outlive this work item.
|
|
220
553
|
const reaction = reactToTriggerMessage({
|
|
@@ -226,46 +559,42 @@ async function observeAcceptedRun(input) {
|
|
|
226
559
|
try {
|
|
227
560
|
let observed;
|
|
228
561
|
try {
|
|
229
|
-
observed = await (input.observeAgent ?? observeIngressAgent)(
|
|
230
|
-
threadId: started.threadId,
|
|
231
|
-
runId: started.runId,
|
|
232
|
-
sourceProvider: input.sourceProvider,
|
|
233
|
-
sourceThreadKey: input.sourceThreadKey,
|
|
234
|
-
userId: input.userId,
|
|
235
|
-
});
|
|
562
|
+
observed = await (input.observeAgent ?? observeIngressAgent)(run);
|
|
236
563
|
}
|
|
237
564
|
catch (error) {
|
|
238
|
-
|
|
239
|
-
|
|
565
|
+
// `rollback` cancels, then deletes, the run a newer message replaced.
|
|
566
|
+
if (replaceable && lookupStatus(error) === 404)
|
|
567
|
+
return replaced();
|
|
568
|
+
await lifecycle("run.failed", missingConnectionFailureMessage(error));
|
|
569
|
+
return { type: "failed", reason: "observe", interrupts: [] };
|
|
570
|
+
}
|
|
571
|
+
const ended = (interrupts = []) => ({
|
|
572
|
+
type: "run",
|
|
573
|
+
run: { id: started.runId, status: observed.status },
|
|
574
|
+
interrupts: interrupts,
|
|
575
|
+
});
|
|
576
|
+
// Stopped from Slack or Studio: the run ended `interrupted`, with nothing
|
|
577
|
+
// waiting on a decision.
|
|
578
|
+
if (isCancelledRun(observed)) {
|
|
579
|
+
if (replaceable && (await wasReplaced(run, input.newerRun)))
|
|
580
|
+
return replaced();
|
|
581
|
+
await lifecycle("run.cancelled");
|
|
582
|
+
return ended();
|
|
240
583
|
}
|
|
584
|
+
// The run reports its own pause and posts its own answer (../delivery.ts).
|
|
241
585
|
if (isInterruptedRun(observed)) {
|
|
242
|
-
|
|
586
|
+
const interrupts = interruptEntries(observed.values).filter((entry) => isRecord(entry) &&
|
|
243
587
|
typeof entry.id === "string" &&
|
|
244
588
|
entry.id.trim().length > 0 &&
|
|
245
|
-
"value" in entry)
|
|
246
|
-
return;
|
|
589
|
+
"value" in entry);
|
|
590
|
+
return ended(interrupts);
|
|
247
591
|
}
|
|
248
592
|
if (observed.status !== "success") {
|
|
249
593
|
await lifecycle("run.failed");
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
const text = extractAssistantText(isRecord(observed.values) ? observed.values : {});
|
|
253
|
-
if (text) {
|
|
254
|
-
logger.info(`Channel outgoing action (type=post, delivery_id=${logger.logIdentifier(event.delivery_id)}, channel_id=${logger.logIdentifier(event.channel_id)}, run_id=${logger.logIdentifier(started.runId)})`);
|
|
255
|
-
const action = await bestEffort(createTriggerTransport(client, { actionId: event.event_id }).post({
|
|
256
|
-
message: { type: "content", content: text },
|
|
257
|
-
target: {
|
|
258
|
-
channel_id: event.channel_id,
|
|
259
|
-
address: event.address,
|
|
260
|
-
source_thread_key: event.source_thread_key,
|
|
261
|
-
},
|
|
262
|
-
}));
|
|
263
|
-
if (action === undefined) {
|
|
264
|
-
await lifecycle("run.failed");
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
594
|
+
return ended();
|
|
267
595
|
}
|
|
268
596
|
await lifecycle("run.completed");
|
|
597
|
+
return ended();
|
|
269
598
|
}
|
|
270
599
|
finally {
|
|
271
600
|
await reaction;
|
|
@@ -303,7 +632,7 @@ async function reactToTriggerMessage(input) {
|
|
|
303
632
|
reaction: { emoji, message_id: id },
|
|
304
633
|
}));
|
|
305
634
|
}
|
|
306
|
-
function runtimeEvent(type, event, started,
|
|
635
|
+
function runtimeEvent(type, event, started, message, tracerSessionId) {
|
|
307
636
|
return {
|
|
308
637
|
id: randomUUID(),
|
|
309
638
|
type,
|
|
@@ -314,19 +643,15 @@ function runtimeEvent(type, event, started, interrupts, message, tracerSessionId
|
|
|
314
643
|
run_id: started.runId,
|
|
315
644
|
...(tracerSessionId ? { tracer_session_id: tracerSessionId } : {}),
|
|
316
645
|
...(message ? { message: { text: message } } : {}),
|
|
317
|
-
...(interrupts?.length ? { interrupts } : {}),
|
|
318
646
|
};
|
|
319
647
|
}
|
|
320
|
-
function missingConnectionFailureMessage(error) {
|
|
648
|
+
export function missingConnectionFailureMessage(error) {
|
|
321
649
|
const slug = missingWorkspaceConnectionSlug(String(error));
|
|
322
650
|
if (slug === undefined) {
|
|
323
651
|
return undefined;
|
|
324
652
|
}
|
|
325
653
|
return `This agent can't respond because the \`${slug}\` connection isn't configured. An agent developer can configure it with \`mda connections create ${slug} --project <project>\`, then try again.`;
|
|
326
654
|
}
|
|
327
|
-
function triggerThreadId(sourceThreadKey) {
|
|
328
|
-
return uuidv5(sourceThreadKey, uuidv5.URL);
|
|
329
|
-
}
|
|
330
655
|
function resolveAssistantId(override) {
|
|
331
656
|
return override?.trim() || process.env[ASSISTANT_ID_ENV]?.trim() || undefined;
|
|
332
657
|
}
|
|
@@ -350,8 +675,20 @@ async function bestEffort(promise) {
|
|
|
350
675
|
return undefined;
|
|
351
676
|
}
|
|
352
677
|
}
|
|
353
|
-
|
|
354
|
-
|
|
678
|
+
/** Whether a newer run replaced a cancelled one; a failed lookup says no. */
|
|
679
|
+
async function wasReplaced(run, newerRun = newerIngressRun) {
|
|
680
|
+
try {
|
|
681
|
+
return await newerRun(run);
|
|
682
|
+
}
|
|
683
|
+
catch (error) {
|
|
684
|
+
logger.warn(`channel run lookup failed; the run counts as stopped (${logger.safeErrorLabel(error)})`);
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
function isCancelledRun(observed) {
|
|
689
|
+
// A cancelled run ends "interrupted" with nothing parked for a person to
|
|
690
|
+
// answer; reporting it as an interrupt would post an empty approval prompt.
|
|
691
|
+
return observed.status === "interrupted" && !hasInterrupt(observed.values);
|
|
355
692
|
}
|
|
356
693
|
function isInterruptedRun(observed) {
|
|
357
694
|
// Agent Server can report status "success" after join while values still
|