@dxos/assistant-toolkit 0.8.4-main.ae835ea → 0.8.4-main.bc674ce
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/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1091 -692
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +43 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1090 -692
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +44 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/blueprints/design/design-blueprint.d.ts +17 -3
- package/dist/types/src/blueprints/design/design-blueprint.d.ts.map +1 -1
- package/dist/types/src/blueprints/design/index.d.ts +1 -1
- package/dist/types/src/blueprints/design/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/discord/discord-blueprint.d.ts +13 -13
- package/dist/types/src/blueprints/discord/discord-blueprint.d.ts.map +1 -1
- package/dist/types/src/blueprints/discord/index.d.ts +1 -1
- package/dist/types/src/blueprints/discord/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/linear/index.d.ts +1 -1
- package/dist/types/src/blueprints/linear/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/linear/linear-blueprint.d.ts +13 -13
- package/dist/types/src/blueprints/linear/linear-blueprint.d.ts.map +1 -1
- package/dist/types/src/blueprints/planning/index.d.ts +1 -1
- package/dist/types/src/blueprints/planning/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/planning/planning-blueprint.d.ts +17 -3
- package/dist/types/src/blueprints/planning/planning-blueprint.d.ts.map +1 -1
- package/dist/types/src/blueprints/research/index.d.ts +1 -1
- package/dist/types/src/blueprints/research/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/research/research-blueprint.d.ts +17 -3
- package/dist/types/src/blueprints/research/research-blueprint.d.ts.map +1 -1
- package/dist/types/src/blueprints/testing.d.ts +2 -2
- package/dist/types/src/blueprints/testing.d.ts.map +1 -1
- package/dist/types/src/blueprints/websearch/index.d.ts +1 -1
- package/dist/types/src/blueprints/websearch/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/websearch/websearch-blueprint.d.ts +17 -3
- package/dist/types/src/blueprints/websearch/websearch-blueprint.d.ts.map +1 -1
- package/dist/types/src/blueprints/websearch/websearch-toolkit.d.ts +1 -0
- package/dist/types/src/blueprints/websearch/websearch-toolkit.d.ts.map +1 -1
- package/dist/types/src/{functions/research → crud}/graph.d.ts +14 -11
- package/dist/types/src/crud/graph.d.ts.map +1 -0
- package/dist/types/src/crud/graph.test.d.ts.map +1 -0
- package/dist/types/src/crud/index.d.ts +2 -0
- package/dist/types/src/crud/index.d.ts.map +1 -0
- package/dist/types/src/functions/agent/prompt.d.ts +73 -8
- package/dist/types/src/functions/agent/prompt.d.ts.map +1 -1
- package/dist/types/src/functions/discord/fetch-messages.d.ts +1 -1
- package/dist/types/src/functions/discord/index.d.ts +1 -1
- package/dist/types/src/functions/discord/index.d.ts.map +1 -1
- package/dist/types/src/functions/document/index.d.ts +3 -2
- package/dist/types/src/functions/document/index.d.ts.map +1 -1
- package/dist/types/src/functions/document/read.d.ts +1 -1
- package/dist/types/src/functions/document/read.d.ts.map +1 -1
- package/dist/types/src/functions/document/update.d.ts +1 -1
- package/dist/types/src/functions/document/update.d.ts.map +1 -1
- package/dist/types/src/functions/entity-extraction/entity-extraction.d.ts +126 -125
- package/dist/types/src/functions/entity-extraction/entity-extraction.d.ts.map +1 -1
- package/dist/types/src/functions/entity-extraction/index.d.ts +126 -125
- package/dist/types/src/functions/entity-extraction/index.d.ts.map +1 -1
- package/dist/types/src/functions/exa/data/exa-search-1748337321991.d.ts.map +1 -0
- package/dist/types/src/functions/exa/data/exa-search-1748337331526.d.ts.map +1 -0
- package/dist/types/src/functions/exa/data/exa-search-1748337344119.d.ts.map +1 -0
- package/dist/types/src/functions/exa/data/index.d.ts.map +1 -0
- package/dist/types/src/functions/exa/exa.d.ts +1 -1
- package/dist/types/src/functions/exa/mock.d.ts +1 -1
- package/dist/types/src/functions/github/fetch-prs.d.ts +1 -1
- package/dist/types/src/functions/github/fetch-prs.d.ts.map +1 -1
- package/dist/types/src/functions/linear/index.d.ts +2 -2
- package/dist/types/src/functions/linear/index.d.ts.map +1 -1
- package/dist/types/src/functions/linear/sync-issues.d.ts +2 -2
- package/dist/types/src/functions/linear/sync-issues.d.ts.map +1 -1
- package/dist/types/src/functions/research/document-create.d.ts +9 -0
- package/dist/types/src/functions/research/document-create.d.ts.map +1 -0
- package/dist/types/src/functions/research/index.d.ts +8 -6
- package/dist/types/src/functions/research/index.d.ts.map +1 -1
- package/dist/types/src/functions/research/research-graph.d.ts +9 -8
- package/dist/types/src/functions/research/research-graph.d.ts.map +1 -1
- package/dist/types/src/functions/research/research.d.ts +4 -3
- package/dist/types/src/functions/research/research.d.ts.map +1 -1
- package/dist/types/src/functions/research/types.d.ts +2 -380
- package/dist/types/src/functions/research/types.d.ts.map +1 -1
- package/dist/types/src/functions/tasks/index.d.ts +2 -2
- package/dist/types/src/functions/tasks/index.d.ts.map +1 -1
- package/dist/types/src/functions/tasks/read.d.ts +1 -1
- package/dist/types/src/functions/tasks/read.d.ts.map +1 -1
- package/dist/types/src/functions/tasks/update.d.ts +1 -1
- package/dist/types/src/functions/tasks/update.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/initiative/Initiative.d.ts +84 -0
- package/dist/types/src/initiative/Initiative.d.ts.map +1 -0
- package/dist/types/src/initiative/InitiativeSchema.d.ts +19 -0
- package/dist/types/src/initiative/InitiativeSchema.d.ts.map +1 -0
- package/dist/types/src/initiative/functions/agent.d.ts +37 -0
- package/dist/types/src/initiative/functions/agent.d.ts.map +1 -0
- package/dist/types/src/initiative/functions/getContext.d.ts +17 -0
- package/dist/types/src/initiative/functions/getContext.d.ts.map +1 -0
- package/dist/types/src/initiative/functions/index.d.ts +4 -0
- package/dist/types/src/initiative/functions/index.d.ts.map +1 -0
- package/dist/types/src/{functions/research/create-document.d.ts → initiative/functions/update.d.ts} +3 -3
- package/dist/types/src/initiative/functions/update.d.ts.map +1 -0
- package/dist/types/src/initiative/index.d.ts +1 -0
- package/dist/types/src/initiative/index.d.ts.map +1 -0
- package/dist/types/src/initiative/initiative.test.d.ts +2 -0
- package/dist/types/src/initiative/initiative.test.d.ts.map +1 -0
- package/dist/types/src/sync/sync.d.ts +3 -3
- package/dist/types/src/sync/sync.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -1
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/plugins.d.ts +19 -0
- package/dist/types/src/testing/plugins.d.ts.map +1 -0
- package/dist/types/src/toolkits/AssistantToolkit.d.ts +43 -0
- package/dist/types/src/toolkits/AssistantToolkit.d.ts.map +1 -0
- package/dist/types/src/toolkits/AssistantToolkit.test.d.ts +2 -0
- package/dist/types/src/toolkits/AssistantToolkit.test.d.ts.map +1 -0
- package/dist/types/src/toolkits/SystemToolkit.d.ts +99 -0
- package/dist/types/src/toolkits/SystemToolkit.d.ts.map +1 -0
- package/dist/types/src/toolkits/index.d.ts +3 -0
- package/dist/types/src/toolkits/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +49 -33
- package/src/blueprints/design/design-blueprint.test.ts +17 -20
- package/src/blueprints/design/design-blueprint.ts +4 -6
- package/src/blueprints/design/index.ts +1 -1
- package/src/blueprints/discord/discord-blueprint.ts +4 -6
- package/src/blueprints/discord/index.ts +1 -1
- package/src/blueprints/linear/index.ts +1 -1
- package/src/blueprints/linear/linear-blueprint.ts +4 -6
- package/src/blueprints/planning/index.ts +1 -1
- package/src/blueprints/planning/planning-blueprint.test.ts +17 -20
- package/src/blueprints/planning/planning-blueprint.ts +4 -6
- package/src/blueprints/research/index.ts +1 -1
- package/src/blueprints/research/research-blueprint.ts +25 -19
- package/src/blueprints/testing.ts +2 -2
- package/src/blueprints/websearch/index.ts +2 -1
- package/src/blueprints/websearch/websearch-blueprint.ts +4 -6
- package/src/crud/graph.test.ts +46 -0
- package/src/{functions/research → crud}/graph.ts +32 -40
- package/src/crud/index.ts +5 -0
- package/src/experimental/feed.test.ts +12 -9
- package/src/functions/agent/prompt.ts +39 -22
- package/src/functions/discord/fetch-messages.test.ts +6 -7
- package/src/functions/discord/fetch-messages.ts +11 -10
- package/src/functions/document/index.ts +1 -0
- package/src/functions/document/read.ts +4 -3
- package/src/functions/document/update.ts +7 -4
- package/src/functions/entity-extraction/entity-extraction.conversations.json +6597 -1
- package/src/functions/entity-extraction/entity-extraction.test.ts +16 -23
- package/src/functions/entity-extraction/entity-extraction.ts +51 -31
- package/src/functions/exa/mock.ts +1 -1
- package/src/functions/github/fetch-prs.ts +3 -2
- package/src/functions/linear/linear.test.ts +18 -20
- package/src/functions/linear/sync-issues.ts +14 -12
- package/src/functions/research/document-create.ts +76 -0
- package/src/functions/research/index.ts +1 -2
- package/src/functions/research/research-graph.ts +13 -11
- package/src/functions/research/{instructions-research.tpl → research-instructions.tpl} +14 -6
- package/src/functions/research/research.conversations.json +1 -10714
- package/src/functions/research/research.test.ts +92 -161
- package/src/functions/research/research.ts +88 -54
- package/src/functions/research/types.ts +14 -12
- package/src/functions/tasks/read.ts +4 -3
- package/src/functions/tasks/update.ts +4 -3
- package/src/index.ts +2 -1
- package/src/initiative/Initiative.ts +99 -0
- package/src/initiative/InitiativeSchema.ts +37 -0
- package/src/initiative/functions/agent.ts +57 -0
- package/src/initiative/functions/getContext.ts +74 -0
- package/src/initiative/functions/index.ts +7 -0
- package/src/initiative/functions/update.ts +63 -0
- package/src/initiative/index.ts +3 -0
- package/src/initiative/initiative.conversations.json +1 -0
- package/src/initiative/initiative.test.ts +485 -0
- package/src/sync/sync.ts +38 -30
- package/src/testing/index.ts +1 -1
- package/src/{plugins.tsx → testing/plugins.tsx} +15 -15
- package/src/toolkits/AssistantToolkit.conversations.json +1 -0
- package/src/toolkits/AssistantToolkit.test.ts +94 -0
- package/src/toolkits/AssistantToolkit.ts +70 -0
- package/src/toolkits/SystemToolkit.ts +299 -0
- package/src/toolkits/index.ts +6 -0
- package/dist/types/src/functions/research/create-document.d.ts.map +0 -1
- package/dist/types/src/functions/research/graph.d.ts.map +0 -1
- package/dist/types/src/functions/research/graph.test.d.ts.map +0 -1
- package/dist/types/src/plugins.d.ts +0 -19
- package/dist/types/src/plugins.d.ts.map +0 -1
- package/dist/types/src/testing/data/exa-search-1748337321991.d.ts.map +0 -1
- package/dist/types/src/testing/data/exa-search-1748337331526.d.ts.map +0 -1
- package/dist/types/src/testing/data/exa-search-1748337344119.d.ts.map +0 -1
- package/dist/types/src/testing/data/index.d.ts.map +0 -1
- package/src/functions/research/create-document.ts +0 -69
- package/src/functions/research/graph.test.ts +0 -69
- /package/dist/types/src/{functions/research → crud}/graph.test.d.ts +0 -0
- /package/dist/types/src/{testing → functions/exa}/data/exa-search-1748337321991.d.ts +0 -0
- /package/dist/types/src/{testing → functions/exa}/data/exa-search-1748337331526.d.ts +0 -0
- /package/dist/types/src/{testing → functions/exa}/data/exa-search-1748337344119.d.ts +0 -0
- /package/dist/types/src/{testing → functions/exa}/data/index.d.ts +0 -0
- /package/src/{testing → functions/exa}/data/exa-search-1748337321991.ts +0 -0
- /package/src/{testing → functions/exa}/data/exa-search-1748337331526.ts +0 -0
- /package/src/{testing → functions/exa}/data/exa-search-1748337344119.ts +0 -0
- /package/src/{testing → functions/exa}/data/index.ts +0 -0
|
@@ -6,22 +6,17 @@ import { describe, expect, it } from '@effect/vitest';
|
|
|
6
6
|
import * as Effect from 'effect/Effect';
|
|
7
7
|
import * as Layer from 'effect/Layer';
|
|
8
8
|
|
|
9
|
-
import { AiService
|
|
10
|
-
import {
|
|
9
|
+
import { AiService } from '@dxos/ai';
|
|
10
|
+
import { MemoizedAiService, TestAiService } from '@dxos/ai/testing';
|
|
11
11
|
import { makeToolExecutionServiceFromFunctions, makeToolResolverFromFunctions } from '@dxos/assistant';
|
|
12
12
|
import { Blueprint } from '@dxos/blueprints';
|
|
13
13
|
import { Obj } from '@dxos/echo';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
TracingService,
|
|
21
|
-
} from '@dxos/functions';
|
|
22
|
-
import { TestDatabaseLayer } from '@dxos/functions/testing';
|
|
23
|
-
import { ObjectId, PublicKey } from '@dxos/keys';
|
|
24
|
-
import { DataType } from '@dxos/schema';
|
|
14
|
+
import { Database } from '@dxos/echo';
|
|
15
|
+
import { TestHelpers } from '@dxos/effect/testing';
|
|
16
|
+
import { CredentialsService, FunctionInvocationService, TracingService } from '@dxos/functions';
|
|
17
|
+
import { FunctionInvocationServiceLayerTest, TestDatabaseLayer } from '@dxos/functions-runtime/testing';
|
|
18
|
+
import { ObjectId } from '@dxos/keys';
|
|
19
|
+
import { Message, Organization, Person } from '@dxos/types';
|
|
25
20
|
|
|
26
21
|
import { testToolkit } from '../../blueprints/testing';
|
|
27
22
|
import { ResearchGraph } from '../research';
|
|
@@ -34,17 +29,15 @@ const TestLayer = Layer.mergeAll(
|
|
|
34
29
|
AiService.model('@anthropic/claude-opus-4-0'),
|
|
35
30
|
makeToolResolverFromFunctions([], testToolkit),
|
|
36
31
|
makeToolExecutionServiceFromFunctions(testToolkit, testToolkit.toLayer({}) as any),
|
|
37
|
-
ComputeEventLogger.layerFromTracing,
|
|
38
32
|
).pipe(
|
|
39
|
-
Layer.provideMerge(
|
|
33
|
+
Layer.provideMerge(FunctionInvocationServiceLayerTest({ functions: [entityExtraction] })),
|
|
40
34
|
Layer.provideMerge(
|
|
41
35
|
Layer.mergeAll(
|
|
42
|
-
|
|
36
|
+
TestAiService(),
|
|
43
37
|
TestDatabaseLayer({
|
|
44
|
-
|
|
45
|
-
spaceKey: PublicKey.from('665c420e0dec9aa36c2bedca567afb0778701920e346eaf83ab2bd3403859723'),
|
|
38
|
+
spaceKey: 'fixed',
|
|
46
39
|
indexing: { vector: true },
|
|
47
|
-
types: [Blueprint.Blueprint,
|
|
40
|
+
types: [Blueprint.Blueprint, Message.Message, Person.Person, Organization.Organization, ResearchGraph],
|
|
48
41
|
}),
|
|
49
42
|
CredentialsService.configuredLayer([]),
|
|
50
43
|
TracingService.layerNoop,
|
|
@@ -52,13 +45,13 @@ const TestLayer = Layer.mergeAll(
|
|
|
52
45
|
),
|
|
53
46
|
);
|
|
54
47
|
|
|
55
|
-
describe
|
|
48
|
+
describe('Entity extraction', () => {
|
|
56
49
|
it.effect(
|
|
57
50
|
'call a function to generate a research report',
|
|
58
51
|
Effect.fnUntraced(
|
|
59
52
|
function* (_) {
|
|
60
|
-
const email = yield*
|
|
61
|
-
Obj.make(
|
|
53
|
+
const email = yield* Database.Service.add(
|
|
54
|
+
Obj.make(Message.Message, {
|
|
62
55
|
[Obj.Meta]: {
|
|
63
56
|
tags: ['important'],
|
|
64
57
|
},
|
|
@@ -83,7 +76,7 @@ describe.skip('Entity extraction', () => {
|
|
|
83
76
|
],
|
|
84
77
|
}),
|
|
85
78
|
);
|
|
86
|
-
yield*
|
|
79
|
+
yield* Database.Service.flush({ indexes: true });
|
|
87
80
|
const result = yield* FunctionInvocationService.invokeFunction(entityExtraction, {
|
|
88
81
|
source: email,
|
|
89
82
|
});
|
|
@@ -10,40 +10,50 @@ import * as Schema from 'effect/Schema';
|
|
|
10
10
|
|
|
11
11
|
import { AiService } from '@dxos/ai';
|
|
12
12
|
import { AiSession, makeToolExecutionServiceFromFunctions, makeToolResolverFromFunctions } from '@dxos/assistant';
|
|
13
|
-
import { Filter, Obj, Ref } from '@dxos/echo';
|
|
14
|
-
import {
|
|
13
|
+
import { Filter, Obj, Ref, Type } from '@dxos/echo';
|
|
14
|
+
import { Database } from '@dxos/echo';
|
|
15
|
+
import { defineFunction } from '@dxos/functions';
|
|
16
|
+
import { FunctionInvocationServiceLayerTest } from '@dxos/functions-runtime/testing';
|
|
15
17
|
import { type DXN } from '@dxos/keys';
|
|
16
18
|
import { log } from '@dxos/log';
|
|
17
|
-
import {
|
|
19
|
+
import { type Actor, LegacyOrganization, Message, Organization, Person } from '@dxos/types';
|
|
18
20
|
import { trim } from '@dxos/util';
|
|
19
21
|
|
|
20
|
-
import {
|
|
22
|
+
import { makeGraphWriterHandler, makeGraphWriterToolkit } from '../../crud';
|
|
23
|
+
import { contextQueueLayerFromResearchGraph } from '../research';
|
|
21
24
|
|
|
22
25
|
export default defineFunction({
|
|
23
26
|
key: 'dxos.org/functions/entity-extraction',
|
|
24
27
|
name: 'Entity Extraction',
|
|
25
28
|
description: 'Extracts entities from emails and transcripts.',
|
|
26
29
|
inputSchema: Schema.Struct({
|
|
27
|
-
source:
|
|
30
|
+
source: Message.Message.annotations({
|
|
31
|
+
description: 'Email or transcript to extract entities from.',
|
|
32
|
+
}),
|
|
28
33
|
|
|
29
34
|
// TODO(dmaretskyi): Consider making this an array of blueprints instead.
|
|
30
|
-
instructions: Schema.optional(Schema.String).annotations({
|
|
35
|
+
instructions: Schema.optional(Schema.String).annotations({
|
|
36
|
+
description: 'Instructions extraction process.',
|
|
37
|
+
}),
|
|
31
38
|
}),
|
|
32
39
|
outputSchema: Schema.Struct({
|
|
33
40
|
entities: Schema.optional(
|
|
34
|
-
Schema.Array(Obj
|
|
41
|
+
Schema.Array(Type.Obj).annotations({
|
|
35
42
|
description: 'Extracted entities.',
|
|
36
43
|
}),
|
|
37
44
|
),
|
|
38
45
|
}),
|
|
39
46
|
handler: Effect.fnUntraced(
|
|
40
|
-
function* ({ data: { source, instructions } }) {
|
|
41
|
-
const
|
|
42
|
-
|
|
47
|
+
function* ({ data: { source: message, instructions } }) {
|
|
48
|
+
const tags = Obj.getMeta(message)?.tags;
|
|
49
|
+
const contact = yield* extractContact(message.sender, tags);
|
|
50
|
+
let organization: Organization.Organization | null = null;
|
|
43
51
|
|
|
44
52
|
if (contact && !contact.organization) {
|
|
45
53
|
const created: DXN[] = [];
|
|
46
|
-
const GraphWriterToolkit = makeGraphWriterToolkit({
|
|
54
|
+
const GraphWriterToolkit = makeGraphWriterToolkit({
|
|
55
|
+
schema: [LegacyOrganization],
|
|
56
|
+
}).pipe();
|
|
47
57
|
const GraphWriterHandler = makeGraphWriterHandler(GraphWriterToolkit, {
|
|
48
58
|
onAppend: (dxns) => created.push(...dxns),
|
|
49
59
|
});
|
|
@@ -57,17 +67,22 @@ export default defineFunction({
|
|
|
57
67
|
The extracted organization URL must match the sender's email domain.
|
|
58
68
|
${instructions ? '<user_intructions>' + instructions + '</user_intructions>' : ''},
|
|
59
69
|
`,
|
|
60
|
-
prompt: JSON.stringify({ source, contact }),
|
|
70
|
+
prompt: JSON.stringify({ source: message, contact }),
|
|
61
71
|
toolkit,
|
|
62
72
|
});
|
|
63
73
|
|
|
64
74
|
if (created.length > 1) {
|
|
65
75
|
throw new Error('Multiple organizations created');
|
|
66
76
|
} else if (created.length === 1) {
|
|
67
|
-
organization = yield*
|
|
68
|
-
Obj.
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
organization = yield* Database.Service.resolve(created[0], Organization.Organization);
|
|
78
|
+
Obj.change(organization, (org) => {
|
|
79
|
+
const meta = Obj.getMeta(org);
|
|
80
|
+
meta.tags ??= [];
|
|
81
|
+
meta.tags.push(...(tags ?? []));
|
|
82
|
+
});
|
|
83
|
+
Obj.change(contact, (c) => {
|
|
84
|
+
c.organization = Ref.make(organization!);
|
|
85
|
+
});
|
|
71
86
|
}
|
|
72
87
|
}
|
|
73
88
|
|
|
@@ -83,22 +98,22 @@ export default defineFunction({
|
|
|
83
98
|
).pipe(
|
|
84
99
|
Layer.provide(
|
|
85
100
|
// TODO(dmaretskyi): This should be provided by environment.
|
|
86
|
-
Layer.mergeAll(
|
|
101
|
+
Layer.mergeAll(FunctionInvocationServiceLayerTest()),
|
|
87
102
|
),
|
|
88
103
|
),
|
|
89
104
|
),
|
|
90
105
|
),
|
|
91
106
|
});
|
|
92
107
|
|
|
93
|
-
const extractContact = Effect.fn('extractContact')(function* (
|
|
94
|
-
const name =
|
|
95
|
-
const email =
|
|
108
|
+
const extractContact = Effect.fn('extractContact')(function* (actor: Actor.Actor, tags?: readonly string[]) {
|
|
109
|
+
const name = actor.name;
|
|
110
|
+
const email = actor.email;
|
|
96
111
|
if (!email) {
|
|
97
|
-
log.warn('email is required for contact extraction', {
|
|
112
|
+
log.warn('email is required for contact extraction', { actor });
|
|
98
113
|
return undefined;
|
|
99
114
|
}
|
|
100
115
|
|
|
101
|
-
const
|
|
116
|
+
const existingContacts = yield* Database.Service.runQuery(Filter.type(Person.Person));
|
|
102
117
|
|
|
103
118
|
// Check for existing contact
|
|
104
119
|
// TODO(dmaretskyi): Query filter DSL - https://linear.app/dxos/issue/DX-541/filtercontains-should-work-with-partial-objects
|
|
@@ -111,16 +126,16 @@ const extractContact = Effect.fn('extractContact')(function* (message: DataType.
|
|
|
111
126
|
return existingContact;
|
|
112
127
|
}
|
|
113
128
|
|
|
114
|
-
const newContact = Obj.make(
|
|
115
|
-
[Obj.Meta]: {
|
|
116
|
-
tags: Obj.getMeta(message)?.tags,
|
|
117
|
-
},
|
|
129
|
+
const newContact = Obj.make(Person.Person, {
|
|
130
|
+
...(tags ? { [Obj.Meta]: { tags: [...tags] } } : {}),
|
|
118
131
|
emails: [{ value: email }],
|
|
119
132
|
});
|
|
120
|
-
yield*
|
|
133
|
+
yield* Database.Service.add(newContact);
|
|
121
134
|
|
|
122
135
|
if (name) {
|
|
123
|
-
newContact
|
|
136
|
+
Obj.change(newContact, (c) => {
|
|
137
|
+
c.fullName = name;
|
|
138
|
+
});
|
|
124
139
|
}
|
|
125
140
|
|
|
126
141
|
const emailDomain = email.split('@')[1]?.toLowerCase();
|
|
@@ -131,7 +146,7 @@ const extractContact = Effect.fn('extractContact')(function* (message: DataType.
|
|
|
131
146
|
|
|
132
147
|
log.info('extracted email domain', { emailDomain });
|
|
133
148
|
|
|
134
|
-
const
|
|
149
|
+
const existingOrganisations = yield* Database.Service.runQuery(Filter.type(Organization.Organization));
|
|
135
150
|
const matchingOrg = existingOrganisations.find((org) => {
|
|
136
151
|
if (org.website) {
|
|
137
152
|
try {
|
|
@@ -147,7 +162,10 @@ const extractContact = Effect.fn('extractContact')(function* (message: DataType.
|
|
|
147
162
|
emailDomain.endsWith(`.${websiteDomain}`)
|
|
148
163
|
);
|
|
149
164
|
} catch (e) {
|
|
150
|
-
log.warn('Error parsing website URL', {
|
|
165
|
+
log.warn('Error parsing website URL', {
|
|
166
|
+
website: org.website,
|
|
167
|
+
error: e,
|
|
168
|
+
});
|
|
151
169
|
return false;
|
|
152
170
|
}
|
|
153
171
|
}
|
|
@@ -156,7 +174,9 @@ const extractContact = Effect.fn('extractContact')(function* (message: DataType.
|
|
|
156
174
|
|
|
157
175
|
if (matchingOrg) {
|
|
158
176
|
log.info('found matching organization', { organization: matchingOrg });
|
|
159
|
-
newContact
|
|
177
|
+
Obj.change(newContact, (c) => {
|
|
178
|
+
c.organization = Ref.make(matchingOrg);
|
|
179
|
+
});
|
|
160
180
|
}
|
|
161
181
|
|
|
162
182
|
return newContact;
|
|
@@ -7,7 +7,7 @@ import * as Schema from 'effect/Schema';
|
|
|
7
7
|
|
|
8
8
|
import { defineFunction } from '@dxos/functions';
|
|
9
9
|
|
|
10
|
-
import { SEARCH_RESULTS } from '
|
|
10
|
+
import { SEARCH_RESULTS } from './data';
|
|
11
11
|
|
|
12
12
|
export default defineFunction({
|
|
13
13
|
key: 'dxos.org/function/exa-mock',
|
|
@@ -6,7 +6,7 @@ import * as HttpClient from '@effect/platform/HttpClient';
|
|
|
6
6
|
import * as Effect from 'effect/Effect';
|
|
7
7
|
import * as Schema from 'effect/Schema';
|
|
8
8
|
|
|
9
|
-
import { defineFunction, withAuthorization } from '@dxos/functions';
|
|
9
|
+
import { CredentialsService, defineFunction, withAuthorization } from '@dxos/functions';
|
|
10
10
|
|
|
11
11
|
export default defineFunction({
|
|
12
12
|
key: 'dxos.org/function/github/fetch-prs',
|
|
@@ -21,7 +21,8 @@ export default defineFunction({
|
|
|
21
21
|
}),
|
|
22
22
|
}),
|
|
23
23
|
handler: Effect.fnUntraced(function* ({ data }) {
|
|
24
|
-
const
|
|
24
|
+
const credential = yield* CredentialsService.getCredential({ service: 'github.com' });
|
|
25
|
+
const client = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(credential.apiKey!)));
|
|
25
26
|
|
|
26
27
|
const response = yield* client.get(`https://api.github.com/repos/${data.owner}/${data.repo}/pulls`);
|
|
27
28
|
const json: any = yield* response.json;
|
|
@@ -13,16 +13,16 @@ import { AiService } from '@dxos/ai';
|
|
|
13
13
|
import { AiServiceTestingPreset } from '@dxos/ai/testing';
|
|
14
14
|
import { makeToolExecutionServiceFromFunctions, makeToolResolverFromFunctions } from '@dxos/assistant';
|
|
15
15
|
import { Obj, Query } from '@dxos/echo';
|
|
16
|
-
import {
|
|
16
|
+
import { Database } from '@dxos/echo';
|
|
17
|
+
import { TestHelpers } from '@dxos/effect/testing';
|
|
18
|
+
import { CredentialsService, FunctionInvocationService } from '@dxos/functions';
|
|
19
|
+
import { TracingServiceExt } from '@dxos/functions-runtime';
|
|
17
20
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from '@dxos/functions';
|
|
24
|
-
import { TestDatabaseLayer, testStoragePath } from '@dxos/functions/testing';
|
|
25
|
-
import { DataType } from '@dxos/schema';
|
|
21
|
+
FunctionInvocationServiceLayerTestMocked,
|
|
22
|
+
TestDatabaseLayer,
|
|
23
|
+
testStoragePath,
|
|
24
|
+
} from '@dxos/functions-runtime/testing';
|
|
25
|
+
import { Person, Project, Task } from '@dxos/types';
|
|
26
26
|
|
|
27
27
|
import { LINEAR_ID_KEY, default as fetchLinearIssues } from './sync-issues';
|
|
28
28
|
|
|
@@ -30,21 +30,19 @@ const TestLayer = Layer.mergeAll(
|
|
|
30
30
|
AiService.model('@anthropic/claude-opus-4-0'),
|
|
31
31
|
makeToolResolverFromFunctions([], Toolkit.make()),
|
|
32
32
|
makeToolExecutionServiceFromFunctions(Toolkit.make() as any, Layer.empty as any),
|
|
33
|
-
ComputeEventLogger.layerFromTracing,
|
|
34
33
|
).pipe(
|
|
35
34
|
Layer.provideMerge(
|
|
36
35
|
Layer.mergeAll(
|
|
37
36
|
AiServiceTestingPreset('direct'),
|
|
38
37
|
TestDatabaseLayer({
|
|
39
38
|
// indexing: { vector: true },
|
|
40
|
-
types: [
|
|
39
|
+
types: [Task.Task, Person.Person, Project.Project],
|
|
41
40
|
storagePath: testStoragePath({ name: 'feed-test-13' }),
|
|
42
41
|
}),
|
|
43
42
|
CredentialsService.layerConfig([{ service: 'linear.app', apiKey: Config.redacted('LINEAR_API_KEY') }]),
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
),
|
|
43
|
+
FunctionInvocationServiceLayerTestMocked({
|
|
44
|
+
functions: [fetchLinearIssues],
|
|
45
|
+
}).pipe(Layer.provideMerge(TracingServiceExt.layerLogInfo())),
|
|
48
46
|
FetchHttpClient.layer,
|
|
49
47
|
),
|
|
50
48
|
),
|
|
@@ -55,29 +53,29 @@ describe('Linear', { timeout: 600_000 }, () => {
|
|
|
55
53
|
'sync',
|
|
56
54
|
Effect.fnUntraced(
|
|
57
55
|
function* (_) {
|
|
58
|
-
yield*
|
|
56
|
+
yield* Database.Service.flush({ indexes: true });
|
|
59
57
|
|
|
60
58
|
yield* FunctionInvocationService.invokeFunction(fetchLinearIssues, {
|
|
61
59
|
team: '1127c63a-6f77-4725-9229-50f6cd47321c',
|
|
62
60
|
});
|
|
63
61
|
|
|
64
|
-
const
|
|
62
|
+
const persons = yield* Database.Service.runQuery(Query.type(Person.Person));
|
|
65
63
|
console.log('people', {
|
|
66
64
|
count: persons.length,
|
|
67
65
|
people: persons.map((_) => `(${_.id}) ${Obj.getLabel(_)} [${Obj.getKeys(_, LINEAR_ID_KEY)[0]?.id}]`),
|
|
68
66
|
});
|
|
69
|
-
const
|
|
67
|
+
const projects = yield* Database.Service.runQuery(Query.type(Project.Project));
|
|
70
68
|
console.log('projects', {
|
|
71
69
|
count: projects.length,
|
|
72
70
|
projects: projects.map((_) => `(${_.id}) ${Obj.getLabel(_)} [${Obj.getKeys(_, LINEAR_ID_KEY)[0]?.id}]`),
|
|
73
71
|
});
|
|
74
|
-
const
|
|
72
|
+
const tasks = yield* Database.Service.runQuery(Query.type(Task.Task));
|
|
75
73
|
console.log('tasks', {
|
|
76
74
|
count: tasks.length,
|
|
77
75
|
tasks: tasks.map((_) => `(${_.id}) ${Obj.getLabel(_)} [${Obj.getKeys(_, LINEAR_ID_KEY)[0]?.id}]`),
|
|
78
76
|
});
|
|
79
77
|
|
|
80
|
-
yield*
|
|
78
|
+
yield* Database.Service.flush({ indexes: true });
|
|
81
79
|
},
|
|
82
80
|
Effect.provide(TestLayer),
|
|
83
81
|
TestHelpers.taggedTest('sync'),
|
|
@@ -10,9 +10,10 @@ import * as Function from 'effect/Function';
|
|
|
10
10
|
import * as Schema from 'effect/Schema';
|
|
11
11
|
|
|
12
12
|
import { Filter, Obj, Query, Ref, type Type } from '@dxos/echo';
|
|
13
|
-
import {
|
|
13
|
+
import { Database } from '@dxos/echo';
|
|
14
|
+
import { CredentialsService, defineFunction, withAuthorization } from '@dxos/functions';
|
|
14
15
|
import { log } from '@dxos/log';
|
|
15
|
-
import {
|
|
16
|
+
import { Person, Project, Task } from '@dxos/types';
|
|
16
17
|
|
|
17
18
|
import { syncObjects } from '../../sync';
|
|
18
19
|
import { graphqlRequestBody } from '../../util';
|
|
@@ -35,7 +36,7 @@ query Issues($teamId: String!, $after: DateTimeOrDuration!) {
|
|
|
35
36
|
updatedAt
|
|
36
37
|
description
|
|
37
38
|
assignee { id, name }
|
|
38
|
-
state {
|
|
39
|
+
state {
|
|
39
40
|
name
|
|
40
41
|
}
|
|
41
42
|
project {
|
|
@@ -84,10 +85,11 @@ export default defineFunction({
|
|
|
84
85
|
}),
|
|
85
86
|
}),
|
|
86
87
|
handler: Effect.fnUntraced(function* ({ data }) {
|
|
87
|
-
const
|
|
88
|
+
const credential = yield* CredentialsService.getCredential({ service: 'linear.app' });
|
|
89
|
+
const client = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(credential.apiKey!)));
|
|
88
90
|
|
|
89
91
|
// Get the timestamp that was previosly synced.
|
|
90
|
-
const after = yield* getLatestUpdateTimestamp(data.team,
|
|
92
|
+
const after = yield* getLatestUpdateTimestamp(data.team, Task.Task);
|
|
91
93
|
log.info('will fetch', { after });
|
|
92
94
|
|
|
93
95
|
// Fetch the issues that have changed since the last sync.
|
|
@@ -114,8 +116,8 @@ export default defineFunction({
|
|
|
114
116
|
const getLatestUpdateTimestamp: (
|
|
115
117
|
teamId: string,
|
|
116
118
|
dataType: Type.Obj.Any,
|
|
117
|
-
) => Effect.Effect<string, never,
|
|
118
|
-
const
|
|
119
|
+
) => Effect.Effect<string, never, Database.Service> = Effect.fnUntraced(function* (teamId, dataType) {
|
|
120
|
+
const existingTasks = yield* Database.Service.runQuery(
|
|
119
121
|
Query.type(dataType).select(Filter.foreignKeys(dataType, [{ source: LINEAR_TEAM_ID_KEY, id: teamId }])),
|
|
120
122
|
);
|
|
121
123
|
return Function.pipe(
|
|
@@ -126,8 +128,8 @@ const getLatestUpdateTimestamp: (
|
|
|
126
128
|
);
|
|
127
129
|
});
|
|
128
130
|
|
|
129
|
-
const mapLinearPerson = (person: LinearPerson, { teamId }: { teamId: string }):
|
|
130
|
-
Obj.make(
|
|
131
|
+
const mapLinearPerson = (person: LinearPerson, { teamId }: { teamId: string }): Person.Person =>
|
|
132
|
+
Obj.make(Person.Person, {
|
|
131
133
|
[Obj.Meta]: {
|
|
132
134
|
keys: [
|
|
133
135
|
{
|
|
@@ -143,8 +145,8 @@ const mapLinearPerson = (person: LinearPerson, { teamId }: { teamId: string }):
|
|
|
143
145
|
nickname: person.name,
|
|
144
146
|
});
|
|
145
147
|
|
|
146
|
-
const mapLinearIssue = (issue: LinearIssue, { teamId }: { teamId: string }):
|
|
147
|
-
Obj.make(
|
|
148
|
+
const mapLinearIssue = (issue: LinearIssue, { teamId }: { teamId: string }): Task.Task =>
|
|
149
|
+
Obj.make(Task.Task, {
|
|
148
150
|
[Obj.Meta]: {
|
|
149
151
|
keys: [
|
|
150
152
|
{
|
|
@@ -170,7 +172,7 @@ const mapLinearIssue = (issue: LinearIssue, { teamId }: { teamId: string }): Dat
|
|
|
170
172
|
project: !issue.project
|
|
171
173
|
? undefined
|
|
172
174
|
: Ref.make(
|
|
173
|
-
|
|
175
|
+
Project.make({
|
|
174
176
|
[Obj.Meta]: {
|
|
175
177
|
keys: [
|
|
176
178
|
{
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
|
+
|
|
8
|
+
import { ArtifactId } from '@dxos/assistant';
|
|
9
|
+
import { Obj, Relation } from '@dxos/echo';
|
|
10
|
+
import { Database } from '@dxos/echo';
|
|
11
|
+
import { TracingService, defineFunction } from '@dxos/functions';
|
|
12
|
+
import { log } from '@dxos/log';
|
|
13
|
+
import { Markdown } from '@dxos/plugin-markdown/types';
|
|
14
|
+
import { HasSubject } from '@dxos/types';
|
|
15
|
+
import { trim } from '@dxos/util';
|
|
16
|
+
|
|
17
|
+
export default defineFunction({
|
|
18
|
+
key: 'dxos.org/function/research/document-create',
|
|
19
|
+
name: 'Create research document',
|
|
20
|
+
description: 'Creates a note summarizing the research.',
|
|
21
|
+
inputSchema: Schema.Struct({
|
|
22
|
+
subject: ArtifactId.annotations({
|
|
23
|
+
description: trim`
|
|
24
|
+
ID of the object (organization, contact, etc.) for which the research was performed.
|
|
25
|
+
`,
|
|
26
|
+
}),
|
|
27
|
+
name: Schema.String.annotations({
|
|
28
|
+
description: 'Name of the document.',
|
|
29
|
+
}),
|
|
30
|
+
content: Schema.String.annotations({
|
|
31
|
+
description: trim`
|
|
32
|
+
Content of the note.
|
|
33
|
+
Supports (and are prefered) references to research objects using @ syntax and <object> tags (refer to research blueprint instructions).
|
|
34
|
+
`,
|
|
35
|
+
}),
|
|
36
|
+
}),
|
|
37
|
+
outputSchema: Schema.Struct({
|
|
38
|
+
document: ArtifactId.annotations({
|
|
39
|
+
description: 'DXN of the created document.',
|
|
40
|
+
}),
|
|
41
|
+
}),
|
|
42
|
+
handler: Effect.fnUntraced(function* ({ data: { subject, name, content } }) {
|
|
43
|
+
log.info('Creating research document', { subject, name, content });
|
|
44
|
+
|
|
45
|
+
// TODO(burdon): Auto flush before and after calling function?
|
|
46
|
+
yield* Database.Service.flush({ indexes: true });
|
|
47
|
+
yield* TracingService.emitStatus({ message: 'Creating research document...' });
|
|
48
|
+
|
|
49
|
+
// TODO(burdon): Type check.
|
|
50
|
+
const target = (yield* Database.Service.resolve(ArtifactId.toDXN(subject))) as Obj.Unknown;
|
|
51
|
+
|
|
52
|
+
// Create document.
|
|
53
|
+
const object = yield* Database.Service.add(
|
|
54
|
+
Markdown.make({
|
|
55
|
+
name,
|
|
56
|
+
content,
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Create relation.
|
|
61
|
+
yield* Database.Service.add(
|
|
62
|
+
Relation.make(HasSubject.HasSubject, {
|
|
63
|
+
[Relation.Source]: object,
|
|
64
|
+
[Relation.Target]: target,
|
|
65
|
+
completedAt: new Date().toISOString(),
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
yield* Database.Service.flush({ indexes: true });
|
|
70
|
+
log.info('Created research document', { subject, object });
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
document: Obj.getDXN(object).toString(),
|
|
74
|
+
};
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { default as create$ } from './create
|
|
5
|
+
import { default as create$ } from './document-create';
|
|
6
6
|
import { default as research$ } from './research';
|
|
7
7
|
|
|
8
|
-
export * from './graph';
|
|
9
8
|
export * from './research-graph';
|
|
10
9
|
export * from './types';
|
|
11
10
|
|
|
@@ -7,8 +7,10 @@ import * as Layer from 'effect/Layer';
|
|
|
7
7
|
import * as Schema from 'effect/Schema';
|
|
8
8
|
|
|
9
9
|
import { Obj, Query, Ref, Type } from '@dxos/echo';
|
|
10
|
+
import { Database } from '@dxos/echo';
|
|
11
|
+
import { SystemTypeAnnotation } from '@dxos/echo/internal';
|
|
10
12
|
import { Queue } from '@dxos/echo-db';
|
|
11
|
-
import { ContextQueueService,
|
|
13
|
+
import { ContextQueueService, QueueService } from '@dxos/functions';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Container for a set of ephemeral research results.
|
|
@@ -16,32 +18,32 @@ import { ContextQueueService, DatabaseService, QueueService } from '@dxos/functi
|
|
|
16
18
|
export const ResearchGraph = Schema.Struct({
|
|
17
19
|
queue: Type.Ref(Queue),
|
|
18
20
|
}).pipe(
|
|
19
|
-
Type.
|
|
21
|
+
Type.object({
|
|
20
22
|
typename: 'dxos.org/type/ResearchGraph',
|
|
21
23
|
version: '0.1.0',
|
|
22
24
|
}),
|
|
25
|
+
SystemTypeAnnotation.set(true),
|
|
23
26
|
);
|
|
24
27
|
|
|
25
28
|
export interface ResearchGraph extends Schema.Schema.Type<typeof ResearchGraph> {}
|
|
26
29
|
|
|
27
|
-
export const queryResearchGraph: () => Effect.Effect<ResearchGraph | undefined, never,
|
|
30
|
+
export const queryResearchGraph: () => Effect.Effect<ResearchGraph | undefined, never, Database.Service> = Effect.fn(
|
|
28
31
|
'queryResearchGraph',
|
|
29
32
|
)(function* () {
|
|
30
|
-
const
|
|
33
|
+
const objects = yield* Database.Service.runQuery(Query.type(ResearchGraph));
|
|
31
34
|
return objects.at(0);
|
|
32
35
|
});
|
|
33
36
|
|
|
34
|
-
export const createResearchGraph: () => Effect.Effect<ResearchGraph, never,
|
|
35
|
-
'createResearchGraph'
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
37
|
+
export const createResearchGraph: () => Effect.Effect<ResearchGraph, never, Database.Service | QueueService> =
|
|
38
|
+
Effect.fn('createResearchGraph')(function* () {
|
|
39
|
+
const queue = yield* QueueService.createQueue();
|
|
40
|
+
return yield* Database.Service.add(Obj.make(ResearchGraph, { queue: Ref.fromDXN(queue.dxn) }));
|
|
41
|
+
});
|
|
40
42
|
|
|
41
43
|
export const contextQueueLayerFromResearchGraph = Layer.unwrapEffect(
|
|
42
44
|
Effect.gen(function* () {
|
|
43
45
|
const researchGraph = (yield* queryResearchGraph()) ?? (yield* createResearchGraph());
|
|
44
|
-
const researchQueue = yield*
|
|
46
|
+
const researchQueue = yield* Database.Service.load(researchGraph.queue);
|
|
45
47
|
return ContextQueueService.layer(researchQueue);
|
|
46
48
|
}),
|
|
47
49
|
);
|