mirror of
https://github.com/kennethnym/aris.git
synced 2026-03-20 09:01:19 +00:00
Compare commits
1 Commits
ci/waitlis
...
6715f03057
| Author | SHA1 | Date | |
|---|---|---|---|
|
6715f03057
|
@@ -534,4 +534,68 @@ describe("computeSignals", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("CalDavSource feed item slots", () => {
|
||||||
|
const EXPECTED_SLOT_NAMES = ["insight", "preparation", "crossSource"]
|
||||||
|
|
||||||
|
test("timed event has all three slots with null content", async () => {
|
||||||
|
const objects: Record<string, CalDavDAVObject[]> = {
|
||||||
|
"/cal/work": [{ url: "/cal/work/event1.ics", data: loadFixture("single-event.ics") }],
|
||||||
|
}
|
||||||
|
const client = new MockDAVClient([{ url: "/cal/work", displayName: "Work" }], objects)
|
||||||
|
const source = createSource(client)
|
||||||
|
|
||||||
|
const items = await source.fetchItems(createContext(new Date("2026-01-15T12:00:00Z")))
|
||||||
|
|
||||||
|
expect(items).toHaveLength(1)
|
||||||
|
const item = items[0]!
|
||||||
|
expect(item.slots).toBeDefined()
|
||||||
|
expect(Object.keys(item.slots!).sort()).toEqual([...EXPECTED_SLOT_NAMES].sort())
|
||||||
|
|
||||||
|
for (const name of EXPECTED_SLOT_NAMES) {
|
||||||
|
const slot = item.slots![name]!
|
||||||
|
expect(slot.content).toBeNull()
|
||||||
|
expect(typeof slot.description).toBe("string")
|
||||||
|
expect(slot.description.length).toBeGreaterThan(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test("all-day event has all three slots with null content", async () => {
|
||||||
|
const objects: Record<string, CalDavDAVObject[]> = {
|
||||||
|
"/cal/work": [{ url: "/cal/work/allday.ics", data: loadFixture("all-day-event.ics") }],
|
||||||
|
}
|
||||||
|
const client = new MockDAVClient([{ url: "/cal/work", displayName: "Work" }], objects)
|
||||||
|
const source = createSource(client)
|
||||||
|
|
||||||
|
const items = await source.fetchItems(createContext(new Date("2026-01-15T12:00:00Z")))
|
||||||
|
|
||||||
|
expect(items).toHaveLength(1)
|
||||||
|
const item = items[0]!
|
||||||
|
expect(item.data.isAllDay).toBe(true)
|
||||||
|
expect(item.slots).toBeDefined()
|
||||||
|
expect(Object.keys(item.slots!).sort()).toEqual([...EXPECTED_SLOT_NAMES].sort())
|
||||||
|
|
||||||
|
for (const name of EXPECTED_SLOT_NAMES) {
|
||||||
|
expect(item.slots![name]!.content).toBeNull()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test("cancelled event has all three slots with null content", async () => {
|
||||||
|
const objects: Record<string, CalDavDAVObject[]> = {
|
||||||
|
"/cal/work": [{ url: "/cal/work/cancelled.ics", data: loadFixture("cancelled-event.ics") }],
|
||||||
|
}
|
||||||
|
const client = new MockDAVClient([{ url: "/cal/work", displayName: "Work" }], objects)
|
||||||
|
const source = createSource(client)
|
||||||
|
|
||||||
|
const items = await source.fetchItems(createContext(new Date("2026-01-15T12:00:00Z")))
|
||||||
|
|
||||||
|
expect(items).toHaveLength(1)
|
||||||
|
const item = items[0]!
|
||||||
|
expect(item.data.status).toBe("cancelled")
|
||||||
|
expect(item.slots).toBeDefined()
|
||||||
|
expect(Object.keys(item.slots!).sort()).toEqual([...EXPECTED_SLOT_NAMES].sort())
|
||||||
|
|
||||||
|
for (const name of EXPECTED_SLOT_NAMES) {
|
||||||
|
expect(item.slots![name]!.content).toBeNull()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@aris/core"
|
import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource, Slot } from "@aris/core"
|
||||||
|
|
||||||
import { Context, TimeRelevance, UnknownActionError } from "@aris/core"
|
import { Context, TimeRelevance, UnknownActionError } from "@aris/core"
|
||||||
import { DAVClient } from "tsdav"
|
import { DAVClient } from "tsdav"
|
||||||
@@ -7,6 +7,9 @@ import type { CalDavDAVClient, CalDavEventData, CalDavFeedItem } from "./types.t
|
|||||||
|
|
||||||
import { CalDavCalendarKey, type CalendarContext } from "./calendar-context.ts"
|
import { CalDavCalendarKey, type CalendarContext } from "./calendar-context.ts"
|
||||||
import { parseICalEvents } from "./ical-parser.ts"
|
import { parseICalEvents } from "./ical-parser.ts"
|
||||||
|
import crossSourcePrompt from "./prompts/cross-source.txt"
|
||||||
|
import insightPrompt from "./prompts/insight.txt"
|
||||||
|
import preparationPrompt from "./prompts/preparation.txt"
|
||||||
import { CalDavEventStatus, CalDavFeedItemType } from "./types.ts"
|
import { CalDavEventStatus, CalDavFeedItemType } from "./types.ts"
|
||||||
|
|
||||||
// -- Source options --
|
// -- Source options --
|
||||||
@@ -340,6 +343,14 @@ export function computeSignals(
|
|||||||
return { urgency: 0.2, timeRelevance: TimeRelevance.Ambient }
|
return { urgency: 0.2, timeRelevance: TimeRelevance.Ambient }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createEventSlots(): Record<string, Slot> {
|
||||||
|
return {
|
||||||
|
insight: { description: insightPrompt, content: null },
|
||||||
|
preparation: { description: preparationPrompt, content: null },
|
||||||
|
crossSource: { description: crossSourcePrompt, content: null },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createFeedItem(event: CalDavEventData, now: Date, timeZone?: string): CalDavFeedItem {
|
function createFeedItem(event: CalDavEventData, now: Date, timeZone?: string): CalDavFeedItem {
|
||||||
return {
|
return {
|
||||||
id: `caldav-event-${event.uid}${event.recurrenceId ? `-${event.recurrenceId}` : ""}`,
|
id: `caldav-event-${event.uid}${event.recurrenceId ? `-${event.recurrenceId}` : ""}`,
|
||||||
@@ -347,5 +358,6 @@ function createFeedItem(event: CalDavEventData, now: Date, timeZone?: string): C
|
|||||||
timestamp: now,
|
timestamp: now,
|
||||||
data: event,
|
data: event,
|
||||||
signals: computeSignals(event, now, timeZone),
|
signals: computeSignals(event, now, timeZone),
|
||||||
|
slots: createEventSlots(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
packages/aris-source-caldav/src/prompts/cross-source.txt
Normal file
8
packages/aris-source-caldav/src/prompts/cross-source.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
If other feed data (weather, transit, nearby events) would disrupt or materially affect this event, state the connection in one sentence. Infer whether the event is indoor/outdoor/virtual from the title and location. Weather is only relevant if it affects getting to the event or the activity itself (e.g., rain for outdoor events, extreme conditions for physical activities). Return null for indoor or virtual events where weather has no impact. Do not fabricate information you don't have — only reference data present in the feed.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- "rain expected at 5pm — bring an umbrella for the walk to Tooley Street"
|
||||||
|
- "Northern line has delays — leave 15 minutes early"
|
||||||
|
- "your next event is across town — the 40 min gap may not be enough"
|
||||||
|
- null (indoor guitar class with wind outside — weather doesn't affect the event)
|
||||||
|
- null
|
||||||
7
packages/aris-source-caldav/src/prompts/insight.txt
Normal file
7
packages/aris-source-caldav/src/prompts/insight.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
One sentence of actionable insight the user can't already see from the event title, time, and location. Do not restate event details. Do not fabricate information you don't have. Return null if there's nothing non-obvious to say.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- "you have 2 hours free before this starts"
|
||||||
|
- "all 8 attendees accepted — expect a full room"
|
||||||
|
- "third time this has been rescheduled"
|
||||||
|
- null
|
||||||
6
packages/aris-source-caldav/src/prompts/preparation.txt
Normal file
6
packages/aris-source-caldav/src/prompts/preparation.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
A concrete preparation step — something the user should do, bring, or review before this event. Infer only from available event and feed data. Do not restate event details. Do not fabricate information you don't have. Return null if no useful preparation comes to mind.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- "different building from your previous meeting — allow travel time"
|
||||||
|
- "recurring meeting you declined last week — check if you need to attend"
|
||||||
|
- null
|
||||||
4
packages/aris-source-caldav/src/text.d.ts
vendored
Normal file
4
packages/aris-source-caldav/src/text.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.txt" {
|
||||||
|
const content: string
|
||||||
|
export default content
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user